{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 层和块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0219,  0.0057,  0.0060,  0.1366, -0.1715, -0.0044, -0.0745,  0.0006,\n",
       "          0.0549, -0.0221],\n",
       "        [ 0.2636, -0.0846,  0.0409,  0.1918, -0.1147, -0.0139, -0.0928,  0.0388,\n",
       "         -0.0974, -0.1375]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 200,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = nn.Sequential(nn.Linear(15, 256), nn.ReLU(), nn.Linear(256, 10))\n",
    "\n",
    "X = torch.rand(2,15)\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "OrderedDict([('weight',\n",
       "              tensor([[-0.0350, -0.0593,  0.0370,  ..., -0.0527,  0.0254,  0.0486],\n",
       "                      [-0.0466, -0.0598,  0.0375,  ..., -0.0431,  0.0265, -0.0623],\n",
       "                      [-0.0125, -0.0277, -0.0539,  ..., -0.0129,  0.0148,  0.0427],\n",
       "                      ...,\n",
       "                      [-0.0271,  0.0554, -0.0120,  ..., -0.0526,  0.0603, -0.0178],\n",
       "                      [ 0.0026,  0.0177,  0.0449,  ..., -0.0595, -0.0324, -0.0311],\n",
       "                      [-0.0133, -0.0304,  0.0368,  ...,  0.0245, -0.0052, -0.0445]])),\n",
       "             ('bias',\n",
       "              tensor([-0.0487,  0.0591,  0.0402,  0.0533,  0.0613,  0.0455, -0.0195, -0.0198,\n",
       "                      -0.0501,  0.0373]))])"
      ]
     },
     "execution_count": 178,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net[2].state_dict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MLP(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.hidden = nn.Linear(15, 256)\n",
    "        self.out = nn.Linear(256,10)\n",
    "        \n",
    "    def forward(self, X):\n",
    "        return self.out(F.relu(self.hidden(X)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0013,  0.0311,  0.1739, -0.0104, -0.1397, -0.1858, -0.0126, -0.0991,\n",
       "          0.0938, -0.1294],\n",
       "        [-0.0008,  0.0578,  0.0579, -0.0056, -0.0632, -0.1569, -0.0269, -0.1140,\n",
       "          0.0714, -0.1218]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 180,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = MLP()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MLP(\n",
      "  (hidden): Linear(in_features=15, out_features=256, bias=True)\n",
      "  (out): Linear(in_features=256, out_features=10, bias=True)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "print(net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "OrderedDict([('hidden.weight',\n",
       "              tensor([[ 0.2337, -0.1825, -0.0621,  ...,  0.0579,  0.1813, -0.1905],\n",
       "                      [ 0.1267,  0.0784, -0.0674,  ..., -0.0933, -0.0464, -0.1921],\n",
       "                      [ 0.2384,  0.1967,  0.0456,  ...,  0.0501,  0.1816, -0.0730],\n",
       "                      ...,\n",
       "                      [-0.0731, -0.1072,  0.0036,  ...,  0.1298, -0.2309,  0.0410],\n",
       "                      [ 0.1738, -0.0198,  0.2036,  ...,  0.0787, -0.0307, -0.1218],\n",
       "                      [-0.2029, -0.2268,  0.2337,  ...,  0.0508, -0.1572,  0.2495]])),\n",
       "             ('hidden.bias',\n",
       "              tensor([ 0.0873, -0.0089, -0.1941, -0.2227, -0.2485,  0.1478,  0.2023,  0.2079,\n",
       "                      -0.0383,  0.2432, -0.1447, -0.0352,  0.1734, -0.0197,  0.2036, -0.1068,\n",
       "                       0.0980, -0.2444,  0.1748,  0.2406, -0.1264,  0.2179,  0.2204,  0.1282,\n",
       "                       0.0872,  0.1129, -0.1132, -0.1425, -0.2309, -0.1220, -0.1418, -0.1974,\n",
       "                      -0.0034,  0.1537, -0.1034,  0.2425, -0.2265, -0.0416,  0.1856, -0.2433,\n",
       "                       0.1654,  0.0544,  0.1464,  0.0015,  0.1048,  0.1712,  0.0591, -0.0226,\n",
       "                      -0.1993,  0.0507,  0.0703,  0.0698, -0.1152, -0.1776,  0.0095, -0.2574,\n",
       "                       0.0489, -0.0642,  0.0588, -0.1594, -0.0573, -0.2060,  0.1286,  0.0852,\n",
       "                       0.0571, -0.2327, -0.1796, -0.1436, -0.2349, -0.0071, -0.1137, -0.1362,\n",
       "                       0.1483, -0.0239,  0.1191,  0.0912, -0.1959, -0.2409, -0.1534,  0.0093,\n",
       "                       0.1748,  0.1450, -0.1241, -0.1087, -0.1049,  0.0056, -0.0175,  0.2554,\n",
       "                       0.0786,  0.0543,  0.1625,  0.1771, -0.0342,  0.0815,  0.0727,  0.1385,\n",
       "                       0.0005,  0.0435, -0.1079, -0.1370,  0.1756,  0.0816, -0.2133,  0.2379,\n",
       "                       0.0843,  0.2427,  0.0008,  0.1993, -0.0349, -0.0413,  0.0386, -0.2424,\n",
       "                      -0.2371, -0.1874, -0.0645, -0.1709,  0.0815, -0.0410, -0.1744,  0.0435,\n",
       "                      -0.0999,  0.0514, -0.0228,  0.1348, -0.2227,  0.0888, -0.1749, -0.0733,\n",
       "                       0.1300,  0.0021, -0.1551, -0.1249,  0.1553, -0.2340,  0.0067,  0.0282,\n",
       "                      -0.2278,  0.1649,  0.0017, -0.0154, -0.2174, -0.2110,  0.2503,  0.2564,\n",
       "                      -0.1684, -0.1455, -0.0743,  0.0903,  0.1271,  0.0356, -0.0387,  0.1429,\n",
       "                       0.1935,  0.0119, -0.0518,  0.1805, -0.2071,  0.1996, -0.1017, -0.0261,\n",
       "                       0.0523,  0.0348,  0.0394, -0.2081, -0.0902, -0.0435, -0.0573, -0.1708,\n",
       "                      -0.2424, -0.0219,  0.1674, -0.1871, -0.1731, -0.0276,  0.0789, -0.1829,\n",
       "                      -0.0413, -0.1199, -0.0910,  0.1254, -0.2463,  0.2520, -0.0301, -0.2517,\n",
       "                       0.0729, -0.0112, -0.1649, -0.0124,  0.0706, -0.0591, -0.0309, -0.2509,\n",
       "                      -0.0623,  0.1294,  0.0604,  0.1741, -0.0992,  0.1573, -0.0124,  0.1849,\n",
       "                       0.2104,  0.1214,  0.1765,  0.0785,  0.1700,  0.0448, -0.0504,  0.1928,\n",
       "                      -0.0142, -0.1055, -0.0972, -0.1445, -0.1842, -0.1674,  0.0162, -0.2173,\n",
       "                       0.1660,  0.1004, -0.0358,  0.0874, -0.0294, -0.1677, -0.2188,  0.0404,\n",
       "                      -0.1639, -0.0495, -0.1592, -0.1032, -0.0346, -0.0543, -0.2498, -0.1739,\n",
       "                       0.0867,  0.1870,  0.2541,  0.1637,  0.1590,  0.2333, -0.0363,  0.0861,\n",
       "                       0.0542,  0.0147,  0.1346,  0.1910, -0.0390, -0.1069, -0.1091, -0.2359,\n",
       "                      -0.1931,  0.2194, -0.0748,  0.2109,  0.1594, -0.1487,  0.1056,  0.0068])),\n",
       "             ('out.weight',\n",
       "              tensor([[ 0.0534,  0.0214, -0.0302,  ..., -0.0020,  0.0109, -0.0390],\n",
       "                      [-0.0272, -0.0324,  0.0038,  ..., -0.0299,  0.0436, -0.0553],\n",
       "                      [ 0.0064,  0.0165,  0.0071,  ...,  0.0363,  0.0570,  0.0585],\n",
       "                      ...,\n",
       "                      [-0.0316,  0.0508,  0.0232,  ..., -0.0389,  0.0165, -0.0277],\n",
       "                      [-0.0539,  0.0391, -0.0557,  ...,  0.0243,  0.0388,  0.0278],\n",
       "                      [ 0.0241,  0.0308, -0.0581,  ...,  0.0179, -0.0555, -0.0191]])),\n",
       "             ('out.bias',\n",
       "              tensor([-0.0256,  0.0498,  0.0197,  0.0446,  0.0205, -0.0273,  0.0481,  0.0123,\n",
       "                      -0.0068,  0.0400]))])"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net.state_dict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MySequential(nn.Module):\n",
    "    def __init__(self, *args):\n",
    "        super().__init__()\n",
    "        for idx, block in enumerate(args):\n",
    "            # 这里，`block`是`Module`子类的一个实例。我们把它保存在'Module'类的成员变量\n",
    "            # `_modules` 中。`block`的类型是OrderedDict。\n",
    "            self._modules[str(idx)] = block\n",
    "\n",
    "    def forward(self, X):\n",
    "        # OrderedDict保证了按照成员添加的顺序遍历它们\n",
    "        for block in self._modules.values():\n",
    "            X = block(X)\n",
    "        return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0409, -0.2167, -0.0363,  0.0937,  0.1888, -0.1747, -0.1437,  0.2501,\n",
       "          0.0359, -0.0749],\n",
       "        [-0.1972, -0.0676, -0.0610, -0.0380,  0.2086,  0.0099, -0.2390,  0.2297,\n",
       "          0.0498, -0.1382]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 136,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = MySequential(nn.Linear(15,256), nn.ReLU(), nn.Linear(256, 10))\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "OrderedDict([('0.weight',\n",
       "              tensor([[-0.0464, -0.0005,  0.0719,  ..., -0.0111,  0.1039, -0.0354],\n",
       "                      [-0.0100, -0.2559, -0.2190,  ..., -0.2521,  0.0649, -0.0266],\n",
       "                      [-0.1086,  0.0112,  0.1939,  ..., -0.1881, -0.2071,  0.2353],\n",
       "                      ...,\n",
       "                      [ 0.1827,  0.1567,  0.0526,  ..., -0.2028,  0.2284,  0.1589],\n",
       "                      [-0.1819, -0.2185, -0.1448,  ..., -0.1255, -0.0929, -0.2050],\n",
       "                      [-0.0234,  0.1326, -0.2140,  ..., -0.2306, -0.0748,  0.1503]])),\n",
       "             ('0.bias',\n",
       "              tensor([-0.1763, -0.0023, -0.0928, -0.0084, -0.0307,  0.1142,  0.0642,  0.0119,\n",
       "                      -0.1500, -0.0589, -0.0795,  0.0959,  0.1078, -0.1927, -0.2080,  0.2535,\n",
       "                       0.0916, -0.1473, -0.2029, -0.2087, -0.0698, -0.1258, -0.0737, -0.1569,\n",
       "                       0.1547,  0.2412, -0.0742,  0.2116,  0.0719, -0.1606,  0.1349,  0.0883,\n",
       "                      -0.1904,  0.2307, -0.0822, -0.2214,  0.1094,  0.1570, -0.1025,  0.1780,\n",
       "                       0.1543, -0.2180, -0.0740,  0.1318,  0.0402,  0.0859, -0.0085, -0.2346,\n",
       "                       0.2575, -0.0860, -0.1465, -0.1356,  0.1261, -0.0912,  0.1500, -0.1651,\n",
       "                       0.1942,  0.1351,  0.1129,  0.1964,  0.1163, -0.1891,  0.2081, -0.0616,\n",
       "                       0.1592, -0.1887, -0.1968, -0.1195, -0.1601,  0.0596,  0.0411, -0.0170,\n",
       "                      -0.1657, -0.1397, -0.1876, -0.0075,  0.0933,  0.1014,  0.0600, -0.1954,\n",
       "                      -0.1550, -0.0843,  0.1449, -0.1969, -0.2124,  0.1618, -0.0671, -0.1219,\n",
       "                      -0.0105, -0.1495,  0.0290, -0.0704,  0.1818,  0.0077, -0.2212,  0.1000,\n",
       "                       0.2051, -0.0231,  0.0447, -0.0314, -0.0844, -0.2459,  0.1225, -0.1122,\n",
       "                      -0.1299, -0.2264, -0.0573,  0.0925, -0.0558, -0.1920, -0.1100,  0.2458,\n",
       "                       0.1037, -0.1418,  0.0808,  0.0682,  0.1781,  0.1321, -0.0324,  0.1334,\n",
       "                      -0.1313, -0.0731, -0.1187, -0.2450,  0.0236, -0.2431, -0.0223, -0.1945,\n",
       "                       0.0182,  0.0974, -0.1941, -0.2271, -0.2151,  0.0739,  0.1190,  0.1244,\n",
       "                      -0.2522,  0.1144, -0.2335,  0.1009,  0.0471,  0.2170, -0.1449, -0.2178,\n",
       "                      -0.0435,  0.1612, -0.1999, -0.2569,  0.1887, -0.0216, -0.2383, -0.2502,\n",
       "                      -0.2159, -0.0407, -0.1736,  0.2341,  0.1687, -0.0611,  0.0325,  0.0568,\n",
       "                       0.0573, -0.0767,  0.0557,  0.1163, -0.2116,  0.0331, -0.0298,  0.1864,\n",
       "                       0.1673, -0.0660,  0.1651, -0.0082, -0.0358, -0.1728, -0.0728,  0.0951,\n",
       "                      -0.2388, -0.2479, -0.0843, -0.2224,  0.1230,  0.0569,  0.1789,  0.1070,\n",
       "                       0.1183, -0.1154, -0.0387, -0.2208,  0.1997, -0.0902,  0.2254, -0.1782,\n",
       "                       0.2394, -0.1087, -0.1907, -0.1917, -0.1317,  0.1341, -0.0723,  0.2318,\n",
       "                      -0.2469,  0.1277, -0.1583, -0.1338, -0.0078,  0.1292, -0.1982, -0.2235,\n",
       "                      -0.1418, -0.1554, -0.0192, -0.2212, -0.1517, -0.0710, -0.2536, -0.0622,\n",
       "                       0.1631,  0.1902,  0.2283,  0.2195,  0.1946, -0.0945, -0.1322,  0.0592,\n",
       "                      -0.2254, -0.1374,  0.2220, -0.0995,  0.1558,  0.2468,  0.0788, -0.2568,\n",
       "                      -0.2564,  0.0481,  0.1678, -0.1062, -0.0639,  0.0773, -0.2575, -0.2069,\n",
       "                       0.2358,  0.1691,  0.0773,  0.1489, -0.0201,  0.1956, -0.0115,  0.0160,\n",
       "                       0.0973, -0.0623, -0.0278, -0.0485,  0.0125,  0.1753, -0.1071,  0.2339])),\n",
       "             ('2.weight',\n",
       "              tensor([[-0.0297, -0.0357,  0.0468,  ...,  0.0389,  0.0053, -0.0594],\n",
       "                      [ 0.0016, -0.0619, -0.0567,  ...,  0.0132, -0.0307, -0.0472],\n",
       "                      [-0.0030,  0.0415, -0.0404,  ..., -0.0596, -0.0556,  0.0479],\n",
       "                      ...,\n",
       "                      [-0.0009,  0.0499, -0.0325,  ...,  0.0595, -0.0379,  0.0079],\n",
       "                      [-0.0555,  0.0148,  0.0397,  ..., -0.0324, -0.0410,  0.0446],\n",
       "                      [-0.0286, -0.0012,  0.0021,  ..., -0.0322,  0.0027,  0.0358]])),\n",
       "             ('2.bias',\n",
       "              tensor([-0.0262, -0.0164, -0.0625, -0.0007, -0.0123, -0.0315,  0.0618,  0.0231,\n",
       "                       0.0551, -0.0288]))])"
      ]
     },
     "execution_count": 137,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net.state_dict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [],
   "source": [
    "class FixedHiddenMLP(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.rand_weight = torch.rand((15, 15), requires_grad=False)\n",
    "        self.linear = nn.Linear(15, 15)\n",
    "        \n",
    "    def forward(self, X):\n",
    "        X = self.linear(X)\n",
    "        # 使用创建的常量参数以及‘relu’和‘dot’函数\n",
    "        X = F.relu(torch.mm(X, self.rand_weight) + 1)\n",
    "        # 复用全连接层。这相当于两个全连接层共享参数\n",
    "        X = self.linear(X)\n",
    "        while X.abs().sum() > 1:\n",
    "            X /= 2\n",
    "        return X.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(-0.0267, grad_fn=<SumBackward0>)"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = FixedHiddenMLP()\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "FixedHiddenMLP(\n",
       "  (linear): Linear(in_features=15, out_features=15, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(-0.1684, grad_fn=<SumBackward0>)"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class NestMLP(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.net = nn.Sequential(nn.Linear(15, 256), nn.ReLU(),\n",
    "                                nn.Linear(256, 256),nn.ReLU())\n",
    "        self.linear = nn.Linear(256, 32)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        return self.linear(self.net(X))\n",
    "\n",
    "chimera = nn.Sequential(NestMLP(), nn.Linear(32, 15), FixedHiddenMLP())\n",
    "chimera(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Sequential(\n",
       "  (0): NestMLP(\n",
       "    (net): Sequential(\n",
       "      (0): Linear(in_features=15, out_features=256, bias=True)\n",
       "      (1): ReLU()\n",
       "      (2): Linear(in_features=256, out_features=256, bias=True)\n",
       "      (3): ReLU()\n",
       "    )\n",
       "    (linear): Linear(in_features=256, out_features=32, bias=True)\n",
       "  )\n",
       "  (1): Linear(in_features=32, out_features=15, bias=True)\n",
       "  (2): FixedHiddenMLP(\n",
       "    (linear): Linear(in_features=15, out_features=15, bias=True)\n",
       "  )\n",
       ")"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chimera"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# exercise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MySequential(nn.Module):\n",
    "    def __init__(self, *arg):\n",
    "        super().__init__()\n",
    "        self.sequential = []\n",
    "        for block in arg:\n",
    "            self.sequential.append(block)\n",
    "    \n",
    "    def forward(self, X):\n",
    "        for i in range(len(self.sequential)):\n",
    "            X = self.sequential[i](X)\n",
    "        return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-0.0359, -0.2072, -0.0800,  0.1878, -0.1063,  0.0315, -0.1092, -0.3001,\n",
       "         -0.2330, -0.0651],\n",
       "        [-0.0197,  0.0860, -0.0055,  0.1113, -0.0522, -0.0721, -0.1057, -0.2766,\n",
       "         -0.3428, -0.0784]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 139,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = MySequential(nn.Linear(15, 256), nn.ReLU(), nn.Linear(256, 10))\n",
    "net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OrderedDict()\n"
     ]
    }
   ],
   "source": [
    "print(net.state_dict())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'MySequential' object is not subscriptable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-143-985fd2462ad2>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnet\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'MySequential' object is not subscriptable"
     ]
    }
   ],
   "source": [
    "print(net[2].parameters())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 311,
   "metadata": {},
   "outputs": [],
   "source": [
    "class net1(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.hidden1 = nn.Linear(15, 256)\n",
    "        self.hidden2 = nn.Linear(256, 128)\n",
    "        self.out = nn.Linear(128,64)\n",
    "    def forward(self, X):\n",
    "        return self.out(F.relu(self.hidden2(F.relu(self.hidden1(X)))))\n",
    "class net2(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.net = nn.Sequential(nn.Linear(64, 128), nn.ReLU(),\n",
    "                                nn.Linear(128, 32), nn.ReLU())\n",
    "        self.linear = nn.Linear(32, 5)\n",
    "    def forward(self, X):\n",
    "        return self.linear(self.net(X))\n",
    "    \n",
    "class twonet(nn.Module):\n",
    "    def __init__(self, *arg):\n",
    "        super().__init__()\n",
    "        self.sequential = []\n",
    "        for _, net in enumerate(arg):\n",
    "            self.sequential.append(net)\n",
    "    def forward(self, X):\n",
    "        for i in range(len(self.sequential)):\n",
    "            X = self.sequential[i](X)\n",
    "        return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 312,
   "metadata": {},
   "outputs": [],
   "source": [
    "parallenet = MySequential(net1(), net2())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 313,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0282, -0.1617, -0.1763, -0.1331, -0.1507],\n",
       "        [ 0.0326, -0.1585, -0.1707, -0.1313, -0.1496]],\n",
       "       grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 313,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "parallenet(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 329,
   "metadata": {},
   "outputs": [],
   "source": [
    "class net1(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.hidden1 = nn.Linear(15, 256)\n",
    "        self.hidden2 = nn.Linear(256, 128)\n",
    "        self.out = nn.Linear(128,10)\n",
    "    def forward(self, X):\n",
    "        return self.out(F.relu(self.hidden2(F.relu(self.hidden1(X)))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 315,
   "metadata": {},
   "outputs": [],
   "source": [
    "class hypenet(nn.Module):\n",
    "    def __init__(self, module, num_copy):\n",
    "        super().__init__()\n",
    "        self.module = module\n",
    "        self.num = num_copy\n",
    "        self.linear = nn.Linear(10, 15) # 10——net1输出个数，15——net1输入样本数\n",
    "        \n",
    "    def forward(self, X):\n",
    "        for i in range(self.num):\n",
    "            X = self.module(X)\n",
    "            print(X.shape)\n",
    "            X = self.linear(X)\n",
    "        return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 316,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = torch.rand(2,15)\n",
    "net22 = hypenet(net1(), 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 317,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 10])\n",
      "torch.Size([2, 10])\n",
      "torch.Size([2, 10])\n",
      "torch.Size([2, 10])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[-0.1751, -0.2024, -0.0046, -0.1316, -0.1671,  0.2094, -0.1816,  0.1866,\n",
       "         -0.0223, -0.1841, -0.1325,  0.2333, -0.0171, -0.2995, -0.3102],\n",
       "        [-0.1751, -0.2024, -0.0046, -0.1316, -0.1671,  0.2094, -0.1816,  0.1866,\n",
       "         -0.0223, -0.1841, -0.1325,  0.2333, -0.0171, -0.2995, -0.3102]],\n",
       "       grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 317,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net22(X)"
   ]
  },
  {
   "attachments": {
    "%E5%9B%BE%E7%89%87.png": {
     "image/png": "iVBORw0KGgoAAAANSUhEUgAAAu0AAAI2CAYAAADkR7aLAAAgAElEQVR4nOy9X6wk1ZngebRXqgdYudRtVjBpCW9YvWiRZte42+ocyYM9aveICVk8sLtjLCVC/dDaNquel3iYkkbGG7rYqsLTKmEW6DKS444HULbtRmoVyC407rHbFmXHLk6MRwjUpqCrKAxddAG3r7sCUXXr24eIyIw4cU5EZJ7MyD/390k/Vd2MyBMnIqPq/uLL75yjhJg5zp8/L6+++qokSQIAAAAAsDDUssV3neP5559f+gcIAAAAAJsP0u4QSDsAAAAAdAHS7hBIOwAAAAB0AdLuEEg7AAAAAHQB0u4QSDsAAAAAdAHS7hBIOwAAAAB0AdLuEEg7AAAAAHQB0u4QSDsAAAAAdMHipf1XP5XPfWZHbsn43CMXFn7IalyQ41+Y9OGWL/xUXp5Dq0j7cogDT7wgXno/1hmuIQAAwHqhbikI9S2f2ZE/PTUHmy3Gr34qn/vMd+X4r+q210v9y498t9DHcltPHSn3v0nMX37ku8uX9jOBeKESlXM8kHgFboblcll8JaLUvkQ1+8WBJ0r5tfsshMgXpZT4kd6X8mvTEUvgqSnlORJfKVEZs4t32s7sfQcAAIAuUY1S7Rq17V+Q418obMsEvvjgkAr7KXkqf+HUqfLPhnjqyI7ccsSs5Uj7MkiF3CqI0b4otS9BcLVe2uNAPOVJEC/hHDJpV340fi3y1RKkfR7vLZ7Tkq4nAAAATMWSpb0aZeFOy1rK2XfTa+2PtxLSPiYS/8BL+2XxvSsSJ4nEDdIe+WVp7pI48ET5vvjjLH8kvhdI4LuI85KlfcnXFAAAANpjl/ZTp1K5PXXKrRZ8DtKul+zUZdKfOlLfzzppz8tw2pYI1Un77luPy5880pNrticZdf+0vp9d2qOdQiY+VHLo6M1y2399VnbH+1yU5358h9x89FBhP0+CM5M2Lr72kNzx4IfkUKEd7+QUkhfti/KuSBzti1KSkgl2qa++TLaXpDsveTHgX64cr17aI/FtWeHIF+UFEufZcKXSn8f7pILrR+mf+T7TZMjzGvDIz/oQ+dnPZXHOS2as5StxIF5he3kfg4hbv12ok/byeZavheHa2cqNsutJ7TsAAMDyqZf2kqi/LH86y0DSaaTdUB5TkfC8Bt4o7Wkf66S7E2l/OxL/aFm6XaU95Qb54kvZPqM75drK9qK0Pyl3frXaxtTSXhL1VMK94INJP/2yyJvFu6E8pva9eV+a5XIip2m9ti7DRVGftjZ+PHBzLOupSBelvdqm1o9M2CfXQRfveUh7dq56GY9V3BsehpB2AACAlaBB2su143UZbmu0lvZshpeKUFdnfjlu6Ueb0pcuymPik56oUMnhR++Xn727W/MBtCyP2XtFHvrmtWXxj2+XrVDJ1p/9gQQ//bGcqRznMbl9W4na/oj8wcn/JD9+661Clr4lWa15UWwjv5glvyy+uqoJn0nQ3aU9Djy7eBqEvlz2MY0Mm5nIeSS+54mX9WXyulmii/1OS2yKpSgLkPY4EE9/GKk9VwakAgAArAMrIu25mNcPMC3uW834N2fZRbqR9jRL/s/knpebPgC7tJ/75b1y24O/VSqvKWfrz8nTJ2+V6+/Lt23JNQ/cJY+/tVtoI5BbvzYpn9n66u/IXfEr7eW9SdrjK+JZyl82V9qrf0+PY5HfQt+q9eMLkPZiiVAJpB0AAGCdWQlpT6dtbCPs9vYqs8xYogtpf+a717ll2n99VD65rUQ99O/l57uJ7L77M/nKN661lNjsylvnvi9ffvRwKubfeqxynN13/5t8//uflsOhErV9uzzW9gaZKdNuoovymO6kvdznPHvenGnvRNpNmfZaaspjAAAAYGVYurSnsj1dzXs1y94wo4x+vEXXtJ85Ijdt19STn/YN9epKVJjJ1t8dkZuM2wvSbmnj8PBk1o/sgUDn6F1ysu0N0ijt1Zp2Mx9I4JkHnxZpHohqyQjPUdrHA0m1GVWapd1Q067XsJf6OamzL7Zb7nc+J7tbTXv9Z8xAVAAAgHXAvrhSF9KuLaxkXECpOHuNpZ22Wfbxvh3MHpOWt1hmbmmS9uRNeebpvPRlS6554DY59uS/qpX2ra/25BPDE/LCXt4HTdq3r5HeI3fJibN1mX+NFtI+fk3ZZpDJ0Etpxm1kQl8psalm8K3TEy5c2u0zteh16vnc7bYZaorbTbPPlGeX8SSItUy4rfzF0N/SdktpUe2Uj0g7AADAyqDa6alDLHoe+CljteZph6mozL4CTtRl2QEAAGClQNodAmnvnmmnagQbDEAFAABYJzqS9knpy9TzvM8lqtNGIu3ry3jO9BXoy7rCNQQAAFgvFi/tGxxIOwAAAAB0AdLuEEg7AAAAAHQB0u4QSDsAAAAAdAHS7hBIOwAAAAB0AdLuEEg7AAAAAHQB0u4QSDs4EfntVy6lbwAAAAcapN0h1k3aox0lKvQkODPle/dekBOP3Swfui9fYXWGNuZBtC9KidPc4unqrYYVWzs/Fz9b8XT+bQ8HPen1MvqhjNru2xvIcLzNvgosAAAAdA/S7hAHRdp/+OQNmaxvurRfFt+x/XZ0s7DRKOzXSvso7GuirsEKtAAAACsD0u4QB0Pad+XEN5Wo8Eb54xcvLv0cFks30h4HnigvkHjB59Mk7cNBT3qD4Ur0FQAAAOpB2h1i1aV99+wJueuRnlyzrUSFW7K1rUv7rrzwkzvk5qOH0gz6fdfLJ/7ycXllL5EkiSU4rrQMe8ZOx7XO8RXxlIjKqEh1tC/KuyJxlolXStKfC/vEwdXJtkqmPZV1ZcK/POfzSctO6h4MyiUrPemHo/I+o1D6ddsz5iHtabbdVsaTnotS/vLLjQAAADYcpN0hVlra347EP2qS7om0vxnfLocNUn7Dkz+UlZL2MZZMeC7rY1FP9/OCD6ptRPvLLY+pleBm0c6FfTDMXxvKwCLu5rbS/XsGzPJf95CBtAMAAHQF0u4Qqyzto6dvEhUqOfzo/fLcbvpauTzmb2X74fTnu3/xiuwmiVx8+R7xQiXqeLEcIpf3JdWxl6iT9rKIR74lS75saY/8WslN68z7Eo5qtmvZcZvozyXTzoBUAACAlQBpd4hVlvbHvrUlKlTin568Vpb2mkw60r64c2iQ9iTJxd00o0u1dKZulhikHQAAYHNA2h1ilaX92b+6UVSoxHvyR3Ix2ZVXfhHIJ48W5XskRx7IMu0/f0kuWttC2udKQ3mMznBQFnJTpt3GPKWdGWQAAACWC9LuEKss7clLX5QbTFn0gny/+MzHZcuwj3eymFU9SNL+gQTeIgafFpkuc10R70pN+xTv1WAgKgAAwPqAtDvESkt7sivPPnOrXH+fEhUekusfDeT+v/A0+b4oP/rBbZPZY1ZU2sszv0wYDzRtlPZMxittXK3KqDZTzSIEvm4axWr5i2EedW32mPIgUttA02o77lM+Iu0AAABdgbQ7xGpLO6wu6eJKK18nPmUpDwAAACwOpN0hkHaYmcgXtdJCzABUAACAVQJpdwikvR5bWcuYj1yVj9RtN5WvLAO9ZMbQT/9Tddtt9fW+KH9Zc943sMp9AwAAOIAg7Q6BtAMAAABAFyDtDoG0AwAAAEAXIO0OgbQDAAAAQBcg7Q6BtAMAAABAFyDtDoG0bzDGgZiR+MxJviDM1zYOPGawAQAASJB2p0DaN5Sa6RjrFxvqkDgQz3Wu98gXpVR1hdnOqZu3Pt22/D4CAAAsF6TdIZD2TaRJErNVQJc9HeLCpb07WY78huu58nPaAwAALB6k3SGQ9s2jVSb9QKwU2pG0t7yWjWIPAACw4SDtDoG0t+RMIF6oRI0p1i5H4odK/NOF/U/7pX3ik56onSj9M2/juCbW2jG8k+UMdN5G2na2344ugWkWvVlUl7laaCrTKqPah0h85UkQF/fTpDjL0udtlM+33H6JBUhzHHjt2o18UYwnAACAAwzS7hBIexsMUt603STtJclO3zMW80zYJ21o24ttjNs1HHeKDHpr2VwYtgeHXLon5xH5yvLtQV02vYtM+zQPP/nDyLKuNwAAwHJB2h0CaW9DKsfVrHZ5e6O0a5n1ceZc+3tieU8q7cVMbSzBcS0jP0U2d/kDUuulvSTb1vNatrRPcwwGpAIAwMEGaXcIpL0tmbgbS1ccpD17Ldoplt4oYwmNqY0KSHvLbXO8L5B2AACAViDtDoG0z4CllGVaaY92VG2mXaeVtG9Qecx6SDvlMQAAAG1B2h0CaZ8FXdK1MpXxgNIaadfFv/IgUKWVtLeWyPr9It82SHSeLFrau5nasvU3FgxEBQCAAw7S7hBIewsqM8dUZ3YpzegS+hKdCcQzDUQd40lwZrrjtJP2+Uz5uFBpz+ZWt8/s0iztceAZ26j0V5tlZiECz5SPAAAArUDaHQJp74a2wj0f6lbnTGS50z1uJvbZbTLIsgMAACDtLoG0d0O30p7UrsC5/AGom0jdgxIDUAEAAJIEaXcKpL0bOpf2JEnFvVKOEYk/Y8bXVpIyxvPlU3XbV0ZcaxZfyviXftO52uaMr17bOPD4VgMAACBB2p0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHgPkTS+A1Lzi1yTBrEABAFaTdIZD2jhiF0u/1pJcxGNr3HYX98X69Xl/CUctjtF7AJ11cqd1c7U1zjC9yoaZ8asZNXpSo/fVLV6ldh2uR3V+21V9jX9QxJeqJ6vboCZVuK+B9b973ViR+8RiVfmjbjylRxzwJXjOc58MN7azMNKcAAKsB0u4QSHvXDGVQJ+3DwXSiXmSTpD07lyDw1kRUZ2XzpL1u8a7oCSXqiSCVXYu0z1/Sq8fwx98ApIJePmYkvlHSC7wWiNfmgaJmkTMAgIMI0u4QSHvX1Ev7KOxLrx/KaJa2W0v7NCxD2iPxM+mLkfY1o+Z+if1McuOlSrtO/D1P1MPFh4xmaZ+mn5Ff860DAMABA2l3CKS9JVp5S683kGFpn5GE/cJ2q3h3IO2Rb125M83W1q3qmbdTs5JpHIinbdels3QcXbojPz12TT9zZpX289tX5TsfkyqfviLnp7metf2MxFeeBHFxhdVps6rN0l5eidZwLVpdz+zblbrrrX/uJdHMz7XYjuFc8740nfNaS3uLTHzlum7ygycAQHuQdodA2tvQUNKSC/tgOH5tOLCJu6ktTfiLFNpsJJeusTSlMmkSQmsJQ+XrfC1zmgn7ROKr0hn5ZSmsiPe0/VymtNf2M5f1yfXSz72ZKTLtNvlr7Ge1xrzaz0j8oqRXPufJg0nerukeapdVrpf2Ui35w9Ncy1mwlcfU1NW/Foh3zJcor8231rwXrx0lMgAASYK0OwXS3oZUtK0CPQqlr2feR6H0jbXp3ZbH2CTKJu2RrwtkWdrjwNPa06XTJCia+E/bz2VlKRv7aSgFmTqrOi9pr+lnHIinvy8OxKsVSdPnqvWzcty252KXduN+CxT39CGh4fPS69ezn4v9j7/n1bTDgFQAgByk3SGQ9rZk4p7RD0eTbcOBOUu+dtJukq6ycFTb095jKJ2plNh0IO3zy7RvgLQbyp1M5S3lkia97KmNeM5b2pNsppnFPLSlwt6uzCUdQJv1N8+0l/ZJs/O+8SEIaQcAyEHaHQJpn4Gsvn0s3qZMu5UNl/Y2pQBIe8M1b9+fVv00Zdobr7M5094knq7lMZV+1WawZydtt21dut5fU017XZ075TEAADlIu0Mg7bOgi3e1pr39e8s0S3u1jnrMHMpjyq9P6pjNWfLJoMS6mvYKB7A8Js9iV+W8A2lvmjfd8Jnlg1+nlfZ2Dy0tpb1mWsX8es6Uvc5q0c1Z8SomwS9l3hPTYNZprwkAwMEAaXcIpL0FlZljtPKYJBHjYNKCfJcXTLK3s1hpL85yYpvdpTzLiB+lPxflqFhG4QWxoQ7eVGqhD0RtIZkN5RwLp0Npr5zrNNei1UOQoZ3KTDjl45c/17YlHjX75bXgOmPZ1RYrqsuEVwbftsW0cJIqS7zeT6OMa32tqbtnykcAgAlIu0Mg7QAwT7r5diR7yFh1GSbLDgBQAml3CKQdAOZLczmOK3n5zmoP7mQAKgCADtLuEEg7AMyfWAJvEeVMNeVhK0YceBu00i0AwHxA2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpB4D5s6iBqBtE5K/+lJUAAHMGaXcIpL0jtAWabCuiJom+EFNfwlHLY7SeEzqbkq/VwjRN09ZNsaLnNMSBeIXFfjZ3Fo721y9doGkd5vy2T/mYri5qXzwpeqK66JFpRdR8VdPGRZhcyI9hWrlVW4DJ1MfyuZraWdC/HQCAFQZpdwikvWuGMqiT9uFgOlEvsjHSrmVpM4HfzPmuN0/a48Az31uvBeIVVg5NpVZbyfUJi6Rr++jvmzfRE0rUE0G66qlJth8uPChkAu8XvlWIv+dpq6SmK7FWzm2j720AgCpIu0Mg7V1TL+2jsC+9fiijWdpeyOqLS8q0a2zuUvCblm2dZkGhVGSLstso7a8F4i1Y2JPYz/oQW6S9Sir5kfXnvC1jRt72kAMAsIEg7Q6BtLdEK2/p9QYyLO0zkrBf2G4V7w6kPfLHZSW6DKTZWvO2cjuqREnCtNIVU/lK6Tj6g0Tkp8eu6afOtNJ+fvuqfOdjUuXTV+T8NNeztp+R+MqTIM4X/Jll0Z9mac9X/zRey9bXM/t2pe5665976Xrn51psx3CueV9anfv00h5/z2sl0fNhdmkfl89kr5m+VSj/e6L+HwAOBki7QyDtbWgoacmFfTAcvzYc2MTd1JYm/EUKbTaSS9dYmlKZNAmhNbsX+ZqMaZnTytf5VemM/LIUptJZEJYp+mk+ZjNzk/baflZX59TPvZkpMu22b1Ia+1mtMa/2MxK/KOmVaz55MMnbNd1D0zxc2cpjSnXgD2vtP6HE+16UyrS1VnxetJR2Q3lM6f2G8zDdA5TIAMBBAGl3CKS9DaloWwV6FEpfz7yPQukba9O7LY+xSZRN2iNfF8iytMeBp7WnS2eekU2sbUzTz+nq7+dMYz8NpSBTlyjNS9pr+hkH4unva8zumj5XrZ+V405xLpno1tevZ9JbEN5U6osDTy214nOhjbRX+1jsV/reXN5tA2Y3rUQKAMAO0u4QSHtbMnHP6IejybbhwJwlXztpN8lDWUyr7WnvMZTOVEpsWvczL8WYvoZ5fpn2DZB2Q7mTqbylXNKklz21qVVveS5a6UgtsV/KxpvKZ6qDPudFk7TnMl79TKIndJGvawtpB4CDA9LuEEj7DGT17WPxNmXarWy4tBsz7bP102W2FKS9IdNuuh9qs+btBpg2l8cUM9DN10cvoTHVtC+uzr1e2u2z2JjfVx2cWr7WlMcAwEEAaXcIpH0WdPGu1rS3f2+ZZmmv1lGPmUN5TPn1SR2zOUs+GZRYV9NeoUU/U4lc8uC8OUp7nsWuynkH0l4zb7rtM8sHv04r7fUPLbZSEgumEprXAvEM5TF6PXm1/7Ngl/b0YcI+P3ylXr+uHIiBqABwgEDaHQJpb0Fl5hitPCZJxDiYtCDf5QWT7O0sVtqLs5zYZncpzzLiR9UsYLGMwgtiQx28qdRCH4jalBluLudYOB1Ke+VcdeGuuxatHtYM7VRmwikfv/y5tp3K0b5fZbGhymDTuDzA1CbFpYWVTANAi/fQDN/UaAsnVfpp2671Vx9Ua6u7Z8pHADhIIO0OgbQDwDypltosgyUOYJ4GsuwAcMBA2h0CaQeA+dJcjrNwssG3qz24kwGoAHDwQNodAmkHgPkTS+AtI4M8KQNa+YGdkb+hq/wCANhB2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkH2DA2fFaSOPCYJhEAYE1B2h0Cae8IbVXVwdC+b3n11L6EoxXo/yZiWb20Qra65lqIYuTXrBwbiX9MiTpmPufyCp6GfbSVSCcrmU5J3s4T1QcLfRVR80qibVdnBQCAVQNpdwikvWuGMqiT9uFg+aJ+UFZp3Dhpr5HZ2Bd1zJfge55dyAsSHT2hSXn2/sn7YgkeNot3HdETStQTgfW90RMmSbd9dgfgHgUA2DCQdodA2rumXtpHYV96/VBGy+wj0r6WxIEnyjNlvyPxMwGPbdKu81og3jFPgteytr/nVTLrqYBPIe2xnwm5XfhbS3uSSOQvedVVAACYGqTdIZD2lmjlLb3eQIalfUYS9gvbreK9YGnPlm8fU5IaQya2KK5ZRlkZaJ9lvix//TGR7xj462+3PY9IfOVJEKf9TftQfoiIA0+UH6V/Gs+17bWqE9ji8U3XoLmfps+kkgnXr7sm3vm5ltqpnGu6EmhTycis0j4urcnFPfZFlbZPw3ykfdMeugAADgJIu0Mg7W1oKGnJhX0wHL82HNjE3dSWJvxFCm02UikZyJZ0Hwteg7TnOGXa5yXtZQGO/LLMjmU9P7dMfKeqc24tfel1NEt7fT8rn0mln7EEflHS0zaLx5o8mOR9NXyOLT+zttJeKY8pvl5TF9+OemlvXzefPzTN2g8AAOgapN0hkPY2pKJtFehRKH098z4KpW+sTV9cpt1YLlAS0y6kfR4097NaCmIT6xrmJO11/Yz86vuayjr07am0a/Xken9anksrac8Givqlzz8T7Uyic7n2Z7pH2tbDl4/Z6j4BAICVBml3CKS9LZm4Z/TD0WTbcGDOkncq7RaxLAn4emXa11/as286TCVHFSlv2G6sVZ/+XBqlPRN2vUTF9D5bNr7Vvdp2EGtlAGzD9QcAgJUGaXcIpH0Gsvr2sXibMu1WNj3TjrQ3ZdqrfShfa2OmvUna51Ee81ognnGKRbOgmwantqO9tNc/ZFAeAwCwbiDtDoG0z4Iu3tWa9vbvLdMs7dU66jEVAdTrozX5HA+A1KWoWlfdLfOT9krte+V6LVbam6YmrJS+5INNp5X2lg8tdgnOBpraRLoy8NS2f35/1l3XltJe8xAx3ecHAACrAtLuEEh7Cyozx2jlMUkixsGkBfkuL5hkb8dJ2pNqqUVF4kozmfgSxYF4JvHRZjzpVuC7lHa9dKVwXY3bZxjYa2inNBC1WELjBRLls8VYz9WMfb9Mko/pTCTctKiRvgBSKvzmbUUi33LPZBJeOcY4W6/3s352GqZ8BABYP5B2h0DaATaFZX9DkpE9pCy01pwsOwDAWoK0OwTSDrBBLH2l0Pybg0UKNQNQAQDWFaTdIZB2gA0j8pdTNpKXAbUo5XEhDrzlf5sAAAAzgbQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDnUc+Jk6ljUTCwAAwAaCtDvEukl7tKNEhZ4EZ6Z8794LcuKxm+VD9ylR4YxtJInEwVVRSjKuLnE+7PkQB1dFeVeMU/Slq4kuYr7toQxqV5ctoK1GW7vvVOftGeYzz1abLUm6eaVVAAAAmB6k3SEOirT/8MkbMll3kPZofyNEvYhV2uNAvIUv0jOSsF8n4qncz0vUK/eSX55TXP+5fC1YzAcAAMAVpN0hDoa078qJbypR4Y3yxy9enPnYdVnpdcV2TpGvZ5wXQYO0j0Lp9/oSjhZ0/KKMN4h5HHgLXzQIAABg00HaHWLVpX337Am565GeXLOtRIVbsrWtS/uuvPCTO+Tmo4fSDPp918sn/vJxeWUvkSSJJTiutAx7xs70Qlov7ZfFH5fNiCi1Xy4ria+Ip/YlKu2X7RNfEc+Ywf9AAk9KIhn5xWOIJpmXxVdXJYjT95lLeIrbMirnFIlfl2XXSlZ6vYEMtX2Gg/rtKUuW9iSXcV98r+Ehpfabh6ysBqkHAACoBWl3iJWW9rcj8Y+apHsi7W/Gt8thg5Tf8OQPZT7SbpDcHP9ytk8q4l7wwfh9ae17QdzjK+Jpoh35eRu5bOvH1l6P9kuSXjlG4YEg70v5QSM7l3G/LQ8ikV9Ty56WrAyG9ms2HPSk1w9llP08CvsWcTdLe7p/z4BN/l1Ia9ar9e3m/cyZeKQdAACgDUi7Q6yytI+evklUqOTwo/fLc7vpa+XymL+V7YfTn+/+xSuymyRy8eV7xAuVqONFgcrlfbbBpznWTHu0X82sZwI9lrxM2ivS7V2RuJRRL4q6TeaLbRa3Vx8eSn0bZ/vrz6m+FCQbRDoYWq7TUAaV7LhN9Jefac/LYtpKOwNSAQAAZgdpd4hVlvbHvrUlKlTin568Vpb2mkx6h9Jufj0V8bFAW0tgsvPys32jffG8q+nfK5Ktl+Do5S/ag4KO4eFiemlPpHb2l0rpzIRVlPZ88GlgG4RavIeQdgAAACeQdodYZWl/9q9uFBUq8Z78kVxMduWVXwTyyaNF+R7JkQeyTPvPX5KL1rZWJdNul/Y4SEU98q9KEF8W37sicbRfW9piy7S7Snt9eYxGJukTITdl2m0sWdojX5Q2ENUu5XXlMQAAANAGpN0hVlnak5e+KDeYsugF+X7xmY/LlmEf72RRvhYs7YaylMjXBng2SHsS7Yvy91NZT5JU3oP9mrr5vNZ+CmnXto/nnDcORG0rqNXSF72m3Y67tEe+moj3VJ9ndU5289zt+efHQFQAAABXkHaHWGlpT3bl2WdulevvU6LCQ3L9o4Hc/xeeJt8X5Uc/uG0ye8xSpD0pDTQ1inCTtGfvH0t5tF8aUFp8bTJzjF7z3iTtWhuVbP4E65SPhvIXk3SXZ4/RBpEOB+aBpnqdfJtMe5Ytn1aYU9nXv03IBqUa2qovGULaAQAA2oC0O8RqSzssjbVZUMi0iukirsWiF5oCAADYfJB2h0DawUZaLtKytn2pfVzkwwUDUAEAAOYF0u4QSDvUEQfeigprltwofb8AACAASURBVGFfdAY88jtYGRYAAOBggLQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7BNIOAAAAAF2AtDsE0g7QkgM0KHV1ByCDFe5PWGVmvD8bP+vGdmMJvIYJCxrbiMRf8ZnU1gmk3SGQdpg3o7BvXlSpcd+GhZSWSeQbZ6rJV2Qt0bk45TPppLjKzOKm+kxXz61blGuMtohX7b6Vz6ld380LbJlonvazfvGt+XyutfcV9yf3Z+f35+TYjbN4Ge5P4/ll64OUz6Vphe4W0/I2XvdlXsODB9LuEEh7h/z6P8u/ffC35JpvHYxsWLryaY20DwdLF/V2/xHbf2lYV45dCnOYU76ThaRGEvbrRCeVp9YiVGSDpCjyi/dceg+a+8D9OV+4P6f6LALzA+ME2/2ZCf/4/tR/1q9bzTFaLAYY+Q2rVje2UdM/mAqk3SGQ9g45E4gXKlE7B+QffYO0j8K+9PqhjJbYxza/zOr22TQp6uZ8GqRoFEp/1oe5KaRonte1iyyc7Rjcn/OG+7PdMbPzaBDq2mMX39vQTtNn33yOTRn7Fm2wOvZcQNodAmlvQSbb3sln5dln/oX89rYSdd/1csfpc5N93n5agkd7cs22EhVuyTUP3CbHXr5Yer8y4J1M/6ONT3qiQiX+6fy4kfihEnV88h9ItKNEhb5Eb39b7jp+KD3OQ0fk2b2k0IYnd/8gkFu/dkhUqOTQ1/6NHD+7O935DgeFkpVeVazbfjW8YGnPV0M1fu1u+OVY/E9ff+8E/T/k9Bei7T96d4mIxFeeBHH+NbP5q+ZymYPtl77tl7fhl5VRHvK+WPqqfe6mz3Y4qN+e0oEURf7kemm/hMufveVaZlk36/2VFD8v83GSYh9M198LJK7pp/F+r+zD/cn9ueT7s1a26+/PyT3q13yTVHdP6NekXqgb/z00tsEK2fMAaXcIpL0FmXTf+I1PyQ1F6d72JdpLJEliOfLAVlXKtz8tD76TzFnaf18+9Y2t2jZ0tnYi2W17rk2/kLJfjINh/lrNV8VGaU9/IZYeCnIGw9afSbWuVSsfaJD2UjsOmZX5SFH5l67eJ/1rXXtNr6MU1f5STD/nyedeZTgoP+Cl4xVMYmSWovL4hjZyZSCXjPH1qikrsZ1v5Wty/bpWvyav3Ee6yOhtTtPPuu3cn9yfy74/66S9VWY6v8eavoFoeGhr8YAwfhixHqO5jTjwVujbq/UEaXcIpL0FBem+4YnvyLnknNz/50pU6ElwJpFkdKdcGyq59htfked2E0n2XpGHvnmtJuFJbXlMe2lXorZvkS+f3ZXdX94t1xXay9vYOna7nHhrV3Z/9e/S4x2f4mvRTMptWaZR2K/ItTVjvrBMu/mXf+kX07ykvSG7YxroN10WxvDLsHRM0y+q+hrRWaWo/lpkg/SsD1ZDGVQe9mwi1W35gVVcLZ9t9Zeydl3jQLyGaxf51c+h1I9p+pnU1Ddzf3J/Lvv+rJP2NuVA42x+G2lnQOomgLQ7BNLegly2j94pT+4Ztp/2jRluJ2nfOyF/aJT2Lfn4My8a+9lG/Fuhfc1c/KVW/nq5poQmSRYo7Zb/vIv/IXcp7XPIZFp/ERm+Bjd+nZ0kslgpSqR2do1KaYL5/klZbSmq7q9d18ZrZyhNyJlBilLxnk2KuD+5Pxd9f7pJe/6tQNBikCfSvikg7Q6BtLegaQBpfLtsZZn2n71bUz+et/PnX5FXNPnPhfufP/287O4+J/c/ejgV/4q0Z9l9Q/tzk/Yi2gwvpkx7/XvXPNPeUfmB/RdR01fCzddlPuUHGsYyqbYis+lSZM5kztLPtNSkadYM7k/uz+Xcn5N9ZyuPKd3fWcZ99nuN8ph1AWl3CKS9BU3Svvek3HnUlGnX/sP9uyNyk6Wm/c2/+bRsmbL1y5Z2/RdU5ZdhDa7SPs7iWb4iLr6u12RqvyzGg7v0/2ybphJryLy0laK8TKGVsJje2yqzY+ur6etz03Vt7suEammBXjNsx12KrNdzDlJUfn2SlZwcq3ydxvdWXc1wi2NX+tkoMdyf3J9LvD9btVVzfxrmZK+d5pKBqBsD0u4QSHsLWkzVuPvW4/Inj+Szx1ikPTknT5+8VXpf3apIe7L3rGw/er0cCpWo+66XW0/eL3cfX4K06zPHmATd8FXz5BecbaBp9Zeci7QnSbVeV/9lXtruR9YMSbmd6n/Y85hSz0WKTOdauibaLBDGRXRK+/gSGepea8+n9jOfUC2fKjy0Ge4t4wDkhUqRrTTAtPDL5BiVzKQ+q4Ypg2f4XMoD/er6qS2sVHOfc39yf3Z/f1oW7mp9f2bnWXk9u+9t/08z5eNGgLQ7BNIO0ETTzB4bRItFSmDV4P6EVWYO9ydZ9o0CaXcIpB2gBY1lNJvD4paJh4XB/QmrjNP9yQDUTQNpdwikHaAlkX9gBiDFgUdGad3g/oRVZsb7s/Gzbmw3lsBreGBobCMSnwfFuYG0OwTSDgAAAABdgLQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7xPnz5+XVV19d+ocIAAAAAJsN0u4Q+/v7cv78eXn++ecBAAAAABYG0k4QBEEQBEEQKx5IO0EQBEEQBEGseCDtBEEQBEEQBLHigbQTBEEQBEEQxIoH0k4QBEEQBEEQKx5IO0EQBEEQBEGseCDtBEEQBEEQBLHigbQTBEEQBEEQxIoH0k4QBEEQBEEQKx5IO0EQBEEQBEGseCDtBEEQBEEQBLHigbQTBEEQBEEQxIoH0k4QBEEQBEEQKx5Iu0Ps7+/L+fPn5fnnnwcAAAAAWBhIu0OcP39eXn31VUmSBAAAAABgYSDtDvH8888v/QMEAAAAgM0HaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAumDx0v6rn8rnPrMjt2R87pELCz9kNS7I8S9M+nDLF34qL8+hVaR9g4l8UX60/H6sM1xDAACAuaFuKQj1LZ/ZkT89NQebLcavfiqf+8x35fivzJufOlI+/i1HDDp96lRzH/N9TO8vxMuPfHf50n4mEC9UonKOBxKvwM1QIdoXpfYlWnY/Oj9vX5TyJIg7Pm4ciKeUeEGs9UV7bUriwBPlTXOPReIrJSpj9mPHEnhufQcAAIAU1STVzjFV+y/Ln+pSrr//1Cm5RWvvqSM7csuRn6bZdKR9fmyYtMfBVVHelYZrnQqrHy2hj5m0FwU7DrwlSHvOHKQ7O6elXE8AAIANYsWkPS1jKZbQpEL+cmWf8WunTmX7X1gfaR8TiY+0d0YbaZ9dcOdxvX1Rni++l2f5Ywk8X4LAcyozWaq0L/uaAgAAbAh2aT91KpXbYmnKLLI7jbRX9jVk3vP+VPriLu0vP/LdqUqE6qR9963H5U8e6ck125OMun9a388u7dFOIRMfKjl09Ga57b8+K7vjfS7Kcz++Q24+eqiwnyfBmUkbF197SO548ENyqNCOd3IKAculPdoXpSSlKL3Rvih1VSsj+UACT8QLPpjs412RuNhG5UEgfY/xGEkm2/7l9M98H/9yua/xFfHUpI3x8fP3F7ZN0PueSqo5KxyJrzwJ4mLpSLmEJs7kOs+OK6Wmk+2sBjwOvLQPcSBe3l6xnaxkxn6M9DxK++jZ+5JE2+S8Xtojv3gM3/5wFwfiWcuNsuuJ1AMAANRSL+0lOU4FeuqBpI3SXh4kWhbml+VPC+996shO4UHilDxlamcVpP3tSPyjZel2lfaUG+SLL2X7jO6Uayvbi9L+pNz51Wob00t7UaIvi18SYk3Qx+8pSHmljUzQx9Kt/5xI5JfFfSzd+T6ZoI/lWv+50s9CO3WZ9jZyWdge+eZSlrFET1sakg/cLMi6HyVlaa/U22eCPhZ3/eeqpM9D2s3nbhP3pochpB0AAKCJBmkvi3G1VKVFzFAeMzlGLu3aA0P+LUDte83RRXlMfNITFSo5/Oj98rN3d2s+gJblMXuvyEPfvLYs/vHtshUq2fqzP5Dgpz+WM5XjPCa3bytR2x+RPzj5n+THb71VyNK3xFAeE/llwdZFWN9uLLHJs+9Jkgm3tj2+Il4hC16V7fLDQp6JL30GBkFvlPbIrxFPQ627tn97GTYzkfNYAs8Tz0vbLkp75Bsy68V+xIF42jnMX9rzbx0ars+M1wEAAACqrJi068dNZV0feGoW79WR9jRL/s/knpebPgC7tJ/75b1y24O/VSqvKWfrz8nTJ2+V6+/Lt23JNQ/cJY+/tVtoI5BbvzYpn9n66u/IXfEr7eW9hbSnWe1csIt/t7dReq1UNmMuXWmS9sg3vd9SZrMW0m74uxdIbGuv+A2B4RzmLu35gFkDSDsAAMBiWE1pL0i16ZhPHTGV6ayOtD/z3evcMu2/Piqf3FaiHvr38vPdRHbf/Zl85RvXWkpsduWtc9+XLz96OBXzbz1WOc7uu/9Nvv/9T8vhUInavl0ea3uDtJL29DUv+CDdX681N7RRkmdTpl1jlkx7u3Y0WpTHdCXt5Wvoj9ttzLR3Ie3GTHsddeUxAAAA0IYVk3ZD3XxWWz+uMzdM+ZjGCtW0nzkiN23X1JOf9g316kpUmMnW3x2Rm4zbC9JuaePw8GTWj+yBQOfoXXKy7Q3SUtrzchbP0wd2mtow18XXSXeTtFdr2uvOx9DHMXWSPT9pr9S+F19vkPZqTXvar8kxyv0cH6vYL63f+YBSl5r2WhiICgAA4Ix9caVOpD0vf2m5cJKhVEZfcbVpppuuZo9Jy1ssM7c0SXvypjzzdF76siXXPHCbHHvyX9VK+9ZXe/KJ4Ql5YS/vgybt29dI75G75MTZusy/Rltpz8XblMU2lL9U5VqbPUYZBqLWSXuSVGaPUYaBqOP+W2ePqZuecPHSbsyi58cxDXhVFtkuzi7jBRJr79dnl/GCWCK/0I4+O02Oqb+lfcylRfVTPiLtAAAAbVDt9NQhFj0P/JSxWvO0bwoGic5Zu7ne9cw1OFGbZQcAAIC2IO0OgbSn1NaKr520J4YSFJgNBqACAADMi46kfVK2MvU873OJ8lzwSPt8mJSa1Ej5Okp7kkzmTF92P9YZriEAAMDcWLy0b3AcdGkHAAAAgG5A2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpByeYXQUOJJH4loW4AADADtLuEOsm7dGOEhV6EpyZ8r17L8iJx26WD92Xr7A6QxvzIFtdtbqi6hTXwG+YorKzc1ncXPDDQU96vYx+KKO2+/YGMlz2danFsCptA+XVYxHFVaF+lVwAADCBtDvEQZH2Hz55Qybrmy7tl8V3bL8d08vnLIzCfq20j8L+Goj6nK5b5CPtK0W68BbfNAEAtAdpd4iDIe27cuKbSlR4o/zxixeXfg6LpRtp7yrL2CTtw0FPeoPhClz3tiDtG0UciMfKwwAArUHaHWLVpX337Am565GeXLOtRIVbsrWtS/uuvPCTO+Tmo4fSDPp918sn/vJxeWUvkSSJJTiutAx7xk7H2bH4ingqX33VINXRvijvisRZJl4pSX8u7BMHVyfbKpn2VNaVCf/ynM8nzTDWiWe5ZKUn/XBU3mcUSr9ue8bypD07xyAQLy9Lify0RKX0sJJKeG35Sv6+AuNrZxDxyLdkb+ukPc77meIF8XyvR+Sn5108l9J1SK9X6bgloW17Pdt/NsbrabrepWuZ37vlNib9tmTPrdfecN4F8tKmxX/zBQCwHiDtDrHS0v52JP5Rk3RPpP3N+HY5bJDyG578oayUtI+xZMJzWR+LerqfF3xQbSPaX255TEN2sUm0c2EfDPPXhjKwiLu5rXT/ngGb/E9PLnW+RLmYe4HEpXNPXy8KWyppBbmr1P1rmfZ5SHsm7JPPvNovZyqCrR+jnbTXX88pPhdbSUrleuv7T2S9/BkU3lO5zi3E3NIfpB0AoAzS7hCrLO2jp28SFSo5/Oj98txu+lq5POZvZfvh9Oe7f/GK7CaJXHz5HvFCJeq4lgU8vsQ69hJ10r6vyZslS75saW8o00jrzPsSjmq2a9lxm+gvO9OeilpRtCPxc8EzXoeylEe+Lnvzl3aTNM69fKmxn+2kvfZ6zuHeM1670ntMAq5/c6R9Rg0PFgxIBQBoD9LuEKss7Y99a0tUqMQ/PXmtLO01mXSkfXHn0KK2OhV384wueulM3SwxqyztZlkrvs8kiPOX9sgvl4qYy1fm/5kvQ9rrBdmSEbf2w/6+4oNQXSa9uU8AAFAEaXeIVZb2Z//qRlGhEu/JH8nFZFde+UUgnzxalO+RHHkgy7T//CW5aG0LaZ8rU5Y0DAdlITdl2m2ssrQ3Z9q7kfYmqZwLKyLti8m0GwYHx4F4ypcoiSXw6vvXyfUHANgQkHaHWGVpT176otxgyqIX5PvFZz4uW4Z9vJNaJu3ASPsHEniLGHxapL7GV6ci3pWa9ineq9Ek7XlN8fT13W0ks1o7HvnlDHc5CzsZtGorvRjPye5U024hH6w6S1a4xcNF+ef8XOcs7Xm7rWvam2vvK+MQCufjeU1CzkBUAIBpQNodYqWlPdmVZ5+5Va6/T4kKD8n1jwZy/194mnxflB/94LbJ7DErKu3lmV8mjAeaNkp7JuOVNq5WhUebqWYRAl9XElAtfzHMo67NHlMeRGobaFptpzHTHhdmK5nqHFtKpjZri61cZjLLSXXmnVJ5ix9pmdvqTCmqJMOWfhgfVAyDMNvS5huBUh88CeLitZqXtCdSfPgxzR5TXozKXArTqowoG3xbe63a1Lsj7QAAY5B2h1htaYfVZQEzlCyETNKoOZYkySXyIM8rPsW3RI1jN6b7xgkAAJB2p0DaYWYqpQgrSJYtRawSGWeoD/QDTFvRbl4EiwGoAADTg7Q7BNJej62sZcxHrspH6rabyleWgV4yY+in/6m67bb6en9FB+E5lIJsILW18quAobynthzI8b6wSnuhH/ViH4nP6rQAAFODtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7BNIOAAAAAF2AtDsE0g4AAAAAXYC0OwTSDgAAAABdgLQ7BNK+wRhndmHWi8VhvrZx4DHlJAAAQIK0OwXSvqHUzKG+MvNLZ9PrOQltm1UrO6FusanmOb8BAAAOAki7QyDtm0iTJGZzmC97zu6FS3t3shz5DddzHRaiAgAAWDBIu0Mg7ZtHq0x6HIi38RLZkbS3vJaNYg8AALDhIO0OgbS35EwgXqhEjSnWLkfih0r804X9T/ulfeKTnqidKP0zb+O4JtbaMbyT5Qx03kbadrbfji6BaRa9WVTbLue+CFKZVtaVJyPxlSdBXNxPk2JtBc3y+ZbbL7EAaY4Dr127kS+K8QQAAHCAQdodAmlvg0HKm7abpL0k2el7xmKeCfukDW17sY1xu4bjTpFBby2bC8P24JBL9+Q8Il9Zvj2oy6Z3kWmf5uEnfxhZ1vUGAABYLki7QyDtbUjluJrVLm9vlHYtsz7OnGt/TyzvSaW9mKmNJTiuZeSnyOYuf0BqvbSXZNt6XsuW9mmOwYBUAAA42CDtDoG0tyUTd2PpioO0Z69FO8XSG2UsoTG1UQFpb7ltjvcF0g4AANAKpN0hkPYZsJSyTCvt0Y6qzbTrtJL2DSqPWQ9ppzwGAACgLUi7QyDts6BLulamMh5QWiPtuvhXHgSqtJL21hJZv1/k2waJzpNFS3s3U1u2/saCgagAAHDAQdodAmlvQWXmmOrMLqUZXUJfojOBeKaBqGM8Cc5Md5x20j6fKR8XKu3Z3Or2mV2apT0OPGMblf5qs8wsROCZ8hEAAKAVSLtDIO3d0Fa450Pd6pyJLHe6x83EPrtNBll2AAAApN0lkPZu6Fbak9oVOJc/AHUTqXtQYgAqAABAkiDtToG0d0Pn0p4kqbhXyjEi8WfM+NpKUsZ4vnyqbvvKiGvN4ksZ/9JvOlfbnPHVaxsHHt9qAAAAJEi7UyDtAAAAANAFSLtDIO0AAAAA0AVIu0Mg7QAAAADQBUi7QyDtAAAAANAFSLtDIO0AAAAA0AVIu0Mg7R0xCqXf60kvYzC07zsK++P9er2+hKNl9n366QrLs8wcrLnJp59OszyTDbPMAADAJoO0OwTS3jVDGdRJ+3CwAqJexGGO8QO4oNDsc+Cz4BUAAGw+SLtDIO1dUy/to7AvvX4oo6X3MwdpnwakHQAAwA7S7hBIe0u08pZebyDD0j4jCfuF7VbxXpS0p9LnB4F4eVlK5BsWAtIXFjJIdf4+06JIBhGPfGVYxMm875g47+dsZSEv/pHIdz5m4I8ut2sj8kV5gQR+fvxIAs+wAJR+LSrnGY/fZ1p4qSrxNjmvl/bIb/jMAAAA1gCk3SGQ9jY0lLTkwj4Yjl8bDmzibmpLE/4ihTbryeXRlygXcy+QOA7EU54EcSK5sBfFMK0/L0hg5Isa7z95z1ylPRP2iRxX+9XEXKQ9O2Zeg+9H2rlUrkV2jcfnqv9clfR5SHvkGx4EEHcAAFhDkHaHQNrbkIq2VaBHofT1zPsolL6xNn2xmfZU+oqiHYmfi6dRostSHvm6OM5f2uPAq+w/e1nJjBT6Vjx2sW/G8yqeUxyIp53f/KW98PnZPhMAAIA1AWl3CKS9LZm4Z/TD0WTbcGDOkq+YtJvFuPg+kzjOX9rLpR7mspIm5pNpr5N2i0QXv7kwnN/cpV0rIzKWLAEAAKwJSLtDIO0zkNW3j8XblGm3ssqZ9m6k3ZRpn5bFS3uLTHsX0m7MtAMAAKwnSLtDIO2zoIt3taa9/XvLNEt7PpBUF7kW0m6oHTfWS49/ngxaHUt7qUa+MCe7U037Emgh7bb6/sn1Kz/QjK9FUdK1axCNB77OXtMOAACwriDtDoG0t6Ayc4xWHpMkYhxMWpDv8oJJ9nYWK+1JtdzCUi4zKcHIZqUpCHapvMWPtMy5YTYVU38NZR+dTnfYRtoTfaEoQx+Ls8t4gcTZrDR6Zr34/tK4AcNMPaaHoGpJEQNRAQBg/UDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJpBwAAAIAuQNodAmkHAAAAgC5A2h0CaQcAAACALkDaHQJp7whtVdXB0L5vefXUvoSjFeg/AAAAgCNIu0Mg7V0zlEGdtA8HiDoAAABsJEi7QyDtXVMv7aOwL71+KKOl9xMAAABgviDtDoG0t0Qrb+n1BjIs7TOSsF/YbhXvBUp75IvyAokjX5RSKV4g8XifSHylxI+09yhfovF2T4LAH783Crz0737Ush+X5a8/JvIdA3/97bbnkvUjTvubnosnQTzZJw487dxiCTwlXhCP/+4HgXhKpecX+Ybr0Y7IV5PrqfJjlK/pZHt+LQv99KP0z8pnkvazcm1LnwkAAMDmgLQ7BNLehoaSllzYB8Pxa8OBTdxNbWnCX6TQZiMVMU2FciKZbaQ9e3+cCa8fTSmR85L2sqhHflm420h72mf9nMry34R+XFM/ixKfyvnkWsWVhx7tPZVrWzyPJd3ve3ty6cIFufTGG3Lp/Pn58sYbcunCBUn29pZ3fgAAsDSQdodA2tuQirZVoEeh9PXM+yiUvrE2fcGZdk2uI78qjE3S7keJJEXBjQPxOs38NvWznbSnfy+2lWfwW/ajSfKNDzPlvlf7Ocm+G891hgeLufLee3Lp9dfl0tmzcuncufTv587Nh7yts2fl0uuvS/Lee8s5RwAAWBpIu0Mg7W3JxD2jH44m24YDc5b8QEr7/DLtS5f2hm8YTEKuZ8qt0q5/a5B9RmWh75i9vYlYv/76YsmOQcYdAOBggbQ7BNI+A1l9+1i8TZl2K0h7Mysi7QvKtJc/k+L1jSXwlphlv3BhnAXvhLNnJblwYTnnCgAASwFpdwikfRZ08a7WtLd/b5lmaa/We49plHatXjouDNQstL0O5TH6z/lg0blKe14bP0VNe2PtfXbNS+eWvc/zlphlT5K03ryLLHsx2/7GG0s7XwAA6B6k3SGQ9hZUZo7RymOSRIyDSQvyXV4wyd7OYqU9mQxWzWW9JORrJO3jwaYTWY/8eUt79TiV2WPGDz6m2XqS8qwxts+t8LnoMt8ll86f717az59f2vkCAED3IO0OgbQDLA5z3buBFZjmsbW0nz+fzi7z3ntyaXc35eJFufTmm0g7AADUgrQ7BNIOsDjaSbvhm4Ul0Era335bLl26JJfefz/98ze/kUv/9E/pz++/n4r8+fNIOwAAGEHaHQJph4OHviBSlXkJdK20F0prljove0ajtL/zTirme3ty6e//viznv/71ZPtvfpPWxyPtAACggbQ7BNIOAEnSIO1vv50K+bvv1ov43/99ut8//iPSDgAAFZB2h0DaASBJaqT9/Pm0FCafx72JXPAvXEDaAQCgBNLuEEg7ACRJjbRfuJBK+FtvtR9k+pvfNEs+0g4AcOBA2h0CaQeAJKmR9vfeSzPtbQeY5vXvSVJf2460AwAcOJB2h0DaASBJaqR9dzfNnBdf+/pn5brPfr2+RCZJ0gGq6yjtkb/Uha4AADYVpN0hkPaO0BZosq2ImiT6Qkx9CUdtj1OeFcU+I0nTSp8wP1pO55jNJLPMWWRqpf2f/qks7Oqjcu8pk4yfknuPKbnu6P8s957VM+1fl8/fq+S6Ar/95Y9K8NoCzif2RR1Top6oinf8PS/dVqSyn7Z6MAAAzAWk3SGQ9q4ZyqBO2oeDKUXdRJNwIO3dsQHSfvFiWtP+61+n4q2UfP7rBmH/+T3yu/feKPcOPyvX/dn/Il967Z+0fb4un7/3o3LvzxebaY+eUKKeCCR4UJQhxwAAIABJREFUuEbaDa/bPpNlz58PALBJIO0OgbR3Tb20j8K+9PqhjJyOQZZwdViNhZPaYJX2X/86lfZ33pHn7rlRrrvxHnnOlGG//7Py+Ouvy6Uf3CbXPfh78qWX3+le2mNfvO/FkiSxu7QnU6xoCwAArUDaHQJpb4lW3tLrDWRY2mckYb+w3Srey5X2yC8sImSQkTjwRPlR+me+n17bW1gUyFaGUzpORVoj8ZUnQZxl/JUSpTwJ4vbn+OIfiXznYwb+6PJU18iPin3Q+hn56TWK/NprVk+TtDeVNLXoZ6vPpPz+yvWOA/mE+qw8fi7NpF+nlFynMgl//fV0fvb3fy73/k+HzFn24vSQP/vf5boHf0/ufVVfZKmbTPv4fOcg7el1ne7eBAAAO0i7QyDtbWgoacmFfTAcvzYc2MTd1JYm/EUKbbanOdNuyyCOZT0Xdb1EoFIykEpn6ViRX5LKtE1foqT8nqJcTpvRnJe0FwW40s9c1sf9MpxrI20z7bbPrEU/W3wmceCXxDPytQeQOJBPZLKeS/njn1WTwabnz8ul+D/I7/4Pvyf3/s0/mIX9zTfTaR6fu1M+fOxmuffspbQWfizu1Zr2T3z7mQX9m22Q9lJNe/HeNH8u6/BNCQDAOoC0OwTS3oZUtK0CPQqlr2feR6H0jbXpq1EeUyvtpdfLbeWZ+DZtjalkK82iXxb7RWO4Rno/DX2KfMM3D7XMR9rr+jnTZ6KfWybtn//6pDzmuXs+Ktd9tFAK8//8a/nw4f9NHn///VTG331XLv3DP6Q17//4j2kJzfvvy6Wf3C4fvvdG+dIv30pnkPmNnnGf1MB/4ssqK2dZwOdrkXad6Ik6cafUDABgniDtDoG0tyUT94x+OJpsGw7MWfINlHa97MVcNlIu+aiWY7jXec8r074J0t7qM9HKZ1J0af+o3HvKUNNemDXmw+qz8viFC6mkX7qUSnmSifk776R/Pvd5uW77d+RLP389XZDp/fdTwTdM+fj4N9qJ9Uz/BlpKe/JaIN4xzzKLDdIOADBPkHaHQNpnIKtvH4u3KdNuZb2l3ZTVNR27tI8l0460t/nMZsu0m/pQ+81GG2k/dY/8rrpRvpRP9Xj+fJpBL2bR33hDLv2//4dc9/Xfk3t/ma2geulSKvkVaT8lX7p/BaQ99kU1SDvlMQAA8wFpdwikfRZ08a7WtLd/b5lmac+z2HWD4xYn7c3T4OmCmNdkz1fa3ZmjtI+z2KYSi8VLe+NnYql5n1raXz8l935Uye/ec6pmn9fl0n/51/Lh47fIvefeT4X9/ffl0oULlf2eG95onqc9v55Os7a0lfZIfMt87sZrDQAATiDtDoG0t6Ayc4xWHpMkYhxMWpDv8oJJ9nacpL04y0mRsWSaylbK8tYo7UliLLWoZnGLM53ks8WUz+EgSbt+zcfHbfzMWvSzxWdSmg1IeRJEgXhTS7uhzr3A4yfSwaUfvlfJh//v/04+fP9/Lx/+s8Py+R/+fWEe98JA1GP3yP9nnD2mOvi2Na8F4ukLJx1Toh6e3NNpDfsEv0bImfIRAGC+IO0OgbQDQJLUzNOuz7WuWmTb21Az5WP6kLHkDDdZdgCAuYO0OwTSDgBJkqT16I3Sng5IvU59VO49NQdpf+MNQ1+ybyeWmuFmACoAwCJA2h0CaQeAJEkkuXBBLp092064v/7ZyRzus3L2rFy6cKHUh8o6Acsi8pffBwCADQRpdwikHQCSJJFkb2+SAXctfWmTZX/9dUn29pZ/3gAA0BlIu0Mg7QAw5r33JlnwXN7PnZsPeVtZNj95773lny8AAHQK0u4QSDsAlNjbS6dofOONdHDqPHnjjbQkhgw7AMCBBGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHeqIA0+8IF56P5ZG5Ivyo+X3AwAAYANA2h1i3aQ92lGiQk+CM1O+d+8FOfHYzfKh+5SocMY2kkTi4KooJRlXJYiXf01ciIOrorwrEhu3eaKUL9HcjzuUQa8nvYx+OLLvOwql33bfqc7bE6U87fOLxFdKk/RYAk8d7AcXAACAOYG0O8RBkfYfPnlDJusO0h7tb4SoF7FKexyIV5HaeTOSsF8n4qncz0vUK/eSr0R5wfjc9Z/L10KJHy3/8wIAAFhnkHaHOBjSvisnvqlEhTfKH794ceZj12Wl1xXbOUW+nnFeBA3SPgql3+tLOFrQ8Ysy3iDmceCZhR4AAABag7Q7xKpL++7ZE3LXIz25ZluJCrdka1uX9l154Sd3yM1HD6UZ9Puul0/85ePyyl4iSRJLcFxpGfaMnemFtF7aL4s/LpsRUWq/XFYSXxFP7UtU2i/bJ74injGD/4EEnpREMvKLxxBNMi+Lr65KEKfvM5fwFLdlVM4pEr8uy66VrPR6Axlq+wwH9dtTliztSS7jvvhew0NK7TcPWVkNUg8AAFAL0u4QKy3tb0fiHzVJ90Ta34xvl8MGKb/hyR/KfKTdILk5/uVsn1TEveCD8fvS2veCuMdXxNNEO/LzNnLZ1o+tvR7tlyS9cozCA0Hel/KDRnYu435bHkQiv6aWPS1ZGQzt12w46EmvH8oo+3kU9i3ibpb2dP+eAZv8u5DWrFfr2837mTPxSDsAAEAbkHaHWGVpHz19k6hQyeFH75fndtPXyuUxfyvbD6c/3/2LV2Q3SeTiy/eIFypRx4sClcv7bINPc6yZ9mi/mlnPBHoseZm0V6TbuyJxKaNeFHWbzBfbLG6vPjyU+jbO9tefU30pSDaIdDC0XKehDCrZcZvoLz/TnpfFtJV2BqQCAADMDtLuEKss7Y99a0tUqMQ/PXmtLO01mfQOpd38eiriY4G2lsBk5+Vn+0b74nlX079XJFsvwdHLX7QHBR3Dw8X00p5I7ewvldKZCaso7fng08A2CLV4DyHtAAAATiDtDrHK0v7sX90oKlTiPfkjuZjsyiu/COSTR4vyPZIjD2SZ9p+/JBetba1Kpt0u7XGQinrkX5Ugviy+d0XiaL+2tMWWaXeV9vryGI1M0idCbsq021iytEe+KG0gql3K68pjAAAAoA1Iu0OssrQnL31RbjBl0Qvy/eIzH5ctwz7eyaJ8LVjaDWUpka8N8GyQ9iTaF+Xvp7KeJKm8B/s1dfN5rf0U0q5tH885bxyI2lZQq6Uvek27HXdpj3w1Ee+pPs/qnOzmudvzz4+BqAAAAK4g7Q6x0tKe7Mqzz9wq19+nRIWH5PpHA7n/LzxNvi/Kj35w22T2mKVIe1IaaGoU4SZpz94/lvJovzSgtPjaZOYYvea9Sdq1NirZ/AnWKR8N5S8m6S7PHqMNIh0OzANN9Tr5Npn2LFs+rTCnsq9/m5ANSjW0VV8yhLQDAAC0AWl3iNWWdlgaa7OgkGkV00Vci0UvNAUAALD5IO0OgbSDjbRcpGVt+1L7uMiHCwagAgAAzAuk3SGQdqgjDrwVFdYsw77oDHjkd7AyLAAAwMEAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdIJF0akfmYq+FmXQAAMARpN0hkPYp2HtBTjx2s3zovnzlVbcVVmfFvJrnFLzzmNxxbEvUfZ+Uo6+vwHVdOtlKqIsQUm0F2cHQvu8o7BdWiG1YCXaJ12k1pwAFAIB1AGl3CKS9PT988oZM1pH2TSIOPFFeIPFCjzOUQZ20DwcrKuoaa7NSLgAArCJIu0Mg7W3ZlRPfVKLCG+WPX7y4Av2B+ZAu0rR4Ca2X9lHYl14/lNHSr0cz3TzkAADAJoK0OwTS3kQswXGlZdgzdiblFLtnT8hdj1wvh0IlKtySa/7jrRL88tykndO+qFCJf/qcfHv4P8qhUMnWV/9XOfKr3dZ9iQNPlFIZs2Ta9XOpflMQ7ShR4R/Kf/jJHfI7X91Kz+WhL8rTb7c/TnzSS69Nds76tUqSRJIzgXjFa3m8KIGR+KEnwZlI/Jq+xic9w+dSuC7aMbyThrKOyK8XUK28pdcbyLC0z0jCfmG7VbwXKO35OUT+5P7wtOupP5hEfuEeisRXngSBP35vlN9rppKhOBDPuhJtVmrk8k0QAABsLEi7QyDtTbSQ9rcflE/fZ9i+/XHZzstPMoH9/W98SrasstqSknC5nItN2qsYhdfCRKYLUhgq8U8X+rGjS3rxGLmsT/oX7WjX6rRf7v9p3yjsk2Pqx8ja9etq2RtKWnJhHwzHrw0HNnE3taUJf5FCm+3uh6Kop5I+qT1vI+3Z+7PyF+VHNfdZKubmbyeQdgAAsIO0OwTS3pZceKuiO3r6JlGhksM7D8lLu4kke6/IiZ3DokIlNz09SvcbZ5235JbvvyC7e0/L3fdrmeG2zCztE1I5t0v7oQcD+dFuIhd/8ofpQ4aeKa8hlfZi/9JrVyf+0U7xGLrkJxUpH2fzx23k2Xnb9uy10kNS08DKVLStAj0Kpa9n3keh9I216QvOtGv3Q/lhpJ20+1FSzqLHgXg10s6AVAAAmBak3SGQ9rbYpT0X3apkFkQ1+3nr4W150bUvC5f2wut5icm00t7wDYKxtGUKadcz7fqDgu0bg+mkPZGxuGf0w9Fk23BgzpIj7QAAAEaQdodA2tsyRaZ99yV5KMu0f/yZv0330yXehXWXdr20JZk+016qlzeU+pgy7cbrUFseo5HVt4/F25Rpt7J50s4MMgAAMC1Iu0Mg7W2xS3ty5ojctG3I6h69XR57J9tnFaRdH/xZIBfkLqS9Uj6TC/gU0h7tNFzLSk37PK6lLt7Vmvb27y3TLO1Z3blpAGijtGuZ8bxufVZpZyAqAADMCNLuEEh7W2qkPUnk3C8DufU/XpMNMj0k1z9yl5w4W5gZxlnacxnSmWIVzxWR9sqA2OOBRKXMeItMu+VcSu8x7FO9/jVTPlZmjtHKY5JEjINJC/JdXjDJ3s5ipT2ZDFbNZb0k5NNJe/2Uj0g7AADYQdodAmmH9cM8sLU6ALYd6VSaSGYrarPsAAAA9SDtDoG0w/phmb5RnxayNVl2uG1t+4GFAagAAOAG0u4QSDusJabymJmEPSeWwCODXEvk82ADAABOIO0OgbQDAAAAQBcg7Q6BtAMAAABAFyDtDoG0AwAAAEAXIO0OgbQDAAAAQBcg7Q6BtAOsE7MOmI3EZ1pLAABYMki7QyDt60E6l7gua9mCO2s3o0e6Oqh9waIC2gJHtfsunBmmPByvPppiXMRpyuOXP2/zPWC6X+oXRQIAAFg8SLtDIO3rQ+SrknTpP68f6WqidhFP5X65ol7EZZ7ympVXW2KV7uzBYNy2/rPW//V7yAMAgE0BaXcIpH2NKMqYVczWiQZpH4XS7/UlHC27nznLlPb69xcf4Gof5ljRFAAAlgjS7hBI+3qRZlt98WfJmD5/RZ76mMh3KlyVnz0/RTtayUqvN5Chts9wUL89ZVHSnsq1H+SlKb5EkZ+WqJRkNss8j8tXDDKrlbcoVZR2g0hHfnq8Sp9qpFs7hvGhIPIbvlXJ2vd983lo58yqpgAAsAyQdodA2teNXDRnyJbORdrTkpXB0L7PcNCTXj+UUfbzKOxbxN0s7en+PQM2+bddI1+ivObbCyQuZZkNpSKRJryVbzN04Z2DtFeOke6nS3Xkt3hIyx9MGvaLA48SGQAAWApIu0Mg7WvGOCu7rBKHbBDpYFizXc+O20R/sZn2VHyLshyJn183Y5lIWcqrcjt/aTcJdLV2vV12PPJVe2lf67EQAACwriDtDoG0rxd5vXIwyyDUeZXH1M3+UimdmbBS0m6R62JGu5rdnr+0j0VbZ1ppzzP2QfNYB6QdAACWBdLuEEj7GpGVPxQHok5Vmzw3aS+QSfpEyE2ZdhurnWnvQtrblqrUl8dkpT7Fgag1c7JTHgMAAMsCaXcIpH1dqM7HbZ67vWuqpS96Tbsdd2nPM9Xlh5cW0m6oaU+vZ0F2SwI+GbQ6OZYm8XFh4Kvl82uuabdgfRgw3Qd18/czEBUAAJYH0u4QSPt6YM6eljOsnfTFUP5iku7y7DHaINLhwDzQVK+TX6i0J+Ntk7IUS7lMYVaXyNeOlQ/+zN8fB+IV2kmFulr+Umqjdoaacl9t0l/Zv/itTGX/ZT/oAQDAQQVpdwikHWA9qHwTMDVk2QEAYLkg7Q6BtAOsC24rmjIAFQAAlg3S7hBIO8A6EUvgzVLeEonvlKUHAABwB2l3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHRbLrLOdbA5x4DE3OgAAQIK0OwXSfhCJJTiuRB1f9JzdpnnFs1VItbnG04WD5ij3ke+4ENE8saxmCgAAcMBA2h0CaT+IuEp7JH6oxD9dv591MZ84EK8osfrP82ClpD3vz8H+xgEAAABpdwikHaanjbTXZ5cjX42Fvvj3ufVx1aQ9P88ZVzMFAADYBJB2h0Da14U0O+6fzrLkYYp3slgrHYkfehKcKe7jSXBm0k60M3mvKdMen/RE7UTpn/l+O1Gh/cL7i+xoMhr5DSKeSb3vkIGOfFFKTSgeL5f24j6G/kS+KrVResjIz6F0HP1BICsBqjlGovdp6fcSAADAckDaHQJpXxcmIj7OcJ/2NSmfSHUu8/FJzy7ntteLEn4mEK+SVW/OtLfKKucyPEv2OQ7Eq5P9vO2xRKcPCaUBoZFfkvS0rr4g1ZU29Br9as1+/bcGkfiUyAAAwAEGaXcIpH1dSKW9nFnPs+/5z6lMl/Y57YsKq9nd9jJvOm6TtKcy2zRjyjjLPbO01xzDkNVufJDQHwRMmfHiNwhxIJ6+vfZhggGpAABwsEHaHQJpXxfs0j55rd0A0SRZAWnPB58GDoNQszaspS2N0p7NZFOihbTnr+nlOaY2SiDtAABwsEHaHQJpXxfayPOqSHtTVjsrKykORHWt9dZnZ2mUdsN0lC0y7aUZcUyZ9loojwEAgIMN0u4QSPu6UJXntP68KI1dSXtWX68PPi1SM+iyOie7ee72SSa9hRi3EO6ytOs17vmA0ro2LO9pW97DQFQAADjgIO0OgbSvC+VZY8yzvzRJu232l4lItpP2ZDxA1Tp7jK0UxFaLnpWalPavk3ZDacrU5TFaG36kZcKbjpFfH6+8j20gKlM+AgDAQQdpdwikfV2wyPMKU5mNZd2YZ2acLDsAAADS7hJI+7qwftI+dfnIqjE30WYAKgAAQJIg7U6BtK8L6yjtWb+9NR18OSdpjwOvcfpLAACAgwDS7hBIOwAAAAB0AdLuEEg7AAAAAHQB0u4QSDsAAAAAdAHS7hBIOwAAAAB0AdLuEEg7wDox68DeSHymnAQAgCWDtDsE0r4eVFcRTcS6kujKM5RBrye9jH44su87CqXfdt8S2bXJqJu9JfJbrrq6dExTaJrvAdP9EgeedeEnAACALkDaHQJpXx8iv7zapv7z+jGSsF8n4qnctxd1E6noboK0W6U7Wzl2PA+8/rN2LdbvIQ8AADYFpN0hkPY1oihjVjFbJxqkfRRKv9eXcORyjGZpXw/qF2gqPsDVPszFgXiVb2wAAAC6AWl3CKR9vUizrb74s2RMn78iT31M5DsVrsrPnp+iHa1kpdcbyFDbZzio356yXGlPS0jyEhpDpj3yU/mN/Ml+FRnOstfW7Vk7hVKdanmLJ0FcbMcg1XlfrOeZSb3vm9/f4noAAAAsGqTdIZD2dSOXuxmypXOR9rRkZTC07zMc9KTXD2WU/TwK+xZxN0t7un/PgE3+m69XraTaVj7NZXssy6kYT9qqlptUs9yR+EVJr3xDMqm9z9s1lcFEfouHtLy/DfvFgUeJDAAALAWk3SGQ9jUjk76ZpH0uZINIB8Oa7Xp23Cb6K1IeUyvt5ddL8hwH4unvayw/0fujPwiYjtsuO57W5reU9rUeCwEAAOsK0u4QSPt6kWdyg1kGoc6rPKZu9pdK6cyEjZN2vexFmctbxjJtnM2mvla99TnkGfygeawD0g4AAMsCaXcIpH2NyCSxOBB1qtrkuUl7gUzSJ0JuyrTbWHNpN2XaNdK6+bqseRtpbyqPycp0igNRa/pFeQwAACwLpN0hkPZ1oToft3nu9q6plr7oNe123KU9z2LbpXyB0t5iCkW9xj0f/DqttFv7aLwP6ubvZyAqAAAsD6TdIZD29cCcPS1nWDvpi6H8xSTd5dljtEGkw4F5oKleJ+8i7bbSFV2460pbGqXd0o4+EFU7fuTPIO22/WzfuBS/lansv+wHPQAAOKgg7Q6BtAOsB9VSm2khyw4AAMsFaXcIpB1gXXBb0ZQBqAAAsGyQdodA2gHWiVgCb5bylkh8pyw9AACAO0i7QyDtAAAAANAFSLtDIO0AAAAA0AVIu0Mg7QAAAADQBUi7QyDtAAAAANAFSLtDIO0AAAAA0AVIu0Mg7QAAAADQBUi7QyDtMMayuqZ5NVYAAACA6UDaHQJp75Bf/2f5tw/+llzzrdkWx+mEyBdVXOZe/xkAAABgRpB2h0DaO+RMIF6oRO2ssLSXVt10W4ETAAAAoAjS7hBIewsy2fZOPivPPvMv5Le3laj7rpc7Tp+b7PP20xI82pNrtpWocEuueeA2OfbyxdL7lQHvZFqKEp/0RIVK/NP5cSPxQyXq+GTZ+WhHiQp9id7+ttx1/FB6nIeOyLN7SaENT+7+QSC3fu2QqFDJoa/9Gzl+dne6840D8ZQnvu9RFgMAAABzA2l3CKS9BZl03/iNT8kNRene9iXaSyRJYjnywFZVyrc/LQ++k8xZ2n9fPvWNrdo2dLZ2Itmd8pzjwBNlqG8HAAAAmBWk3SGQ9hYUpPuGJ74j55Jzcv+fK1GhJ8GZRJLRnXJtqOTab3xFnttNJNl7RR765rWahCe15THtpV2J2r5Fvnx2V3Z/ebdcV2gvb2Pr2O1y4q1d2f3Vv0uPV2ijHVlZDNIOAAAAcwRpdwikvQW5bB+9U57cM2w/7Rsz3E7SvndC/tAo7Vvy8WdeNPazjfi3Ih98GjAIFQAAAOYH0u4QSHsLmgaQxrfLVpZp/9m7NfXjeTt//hV5RZP/XLj/+dPPy+7uc3L/o4dT8a9Ie5bdN7Q/H2mPxFfaQFRv2kw9AAAAQBWk3SGQ9hY0Sfvek3LnUVOmXRvE+XdH5CZLTfubf/Np2TJl6zuW9sqc7Ja52wEAAACmBWl3CKS9BS2matx963H5k0fy2WMs0p6ck6dP3iq9r25VpD3Ze1a2H71eDoXpzDS3nrxf7j7esbRHviilxI+0dgOPMhkAAABwBml3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXcIpB0AAAAAugBpdwikHQAAAAC6AGl3CKQdAAAAALoAaXeI8+fPy6uvvrr0DxEAAAAANhuk3SH29/fl/Pnz8vzzzwMAAAAALAyknSAIgiAIgiBWPJB2giAIgiAIgljxQNoJgiAIgiAIYsUDaScIgiAIgiCIFQ+knSAIgiAIgiBWPJB2giAIgiAIgljxUP/nf/m/BAAAAAAAVhcy7QRBEARBEASx4oG0EwRBEARBEMSKB9JOEARBEARBEP9/e2cfI0d53/Gpqkpt/6sqVap0VZhjKTGvZ1ChlgqOEgidXBpC1CA3aQKlDWmpk6gjdFdSaCEK4JgUkRYbmoYl1DUqcUpQTnHPcWkVXuouITljXnzB5Uxgk4CV3XvdWyRy+fWPmdmbl2eemdnZnZ3b+3ykj8C78/LMM/fHd579Pc+UHEI7AAAAAEDJIbQDAAAAAJQcQjsAAAAAQMkhtOdgbW1N6vW6zMzMICIiIiL2TUJ7Dur1uszNzUm73UZERERE7JuE9hzMzMwM/AYiIiIi4vBLaM8BoR0RERERi5DQngNCOyIiIiIWIaE9B4R2RERERCxCQnsOCO2IiIiIWISE9hwQ2hERERGxCAntOSC0IyIiImIREtpzQGhHRERExCLsf2g/cUTGtz8oY67je0/1/ZRRTsndO9bbMLbjiMz24KiE9s1sVSzDkurA27HR2oaIiIjdaIz5AvXY9gdl53QP0qyfE0dkfPsBufuE+uupyeD5xyYVcXp6OraNkf0Tgvns3gP9De01W0zDENOuBT6vWoYYmzFIVa0Net01sc3ofXSsiqW4x+12W6r7DTF2eXZ73TWx9xhi7DLFPqk49y7/OdTb1WxTDNOW2sD7EREREXuhkRSqc5Pp+LOyM/zgEN5/elrGEo43NRkT/qWA0N5uu0HVFLsW8+8CrVqGGFZ1cH9kQxjaY/u0Zomxf/3z6n5DjD0Zg/NJW8xdptgHLU1oV32ubv9A7z0iIiL2zJKFdqeMxV9CEw3gbqlLTChPOl8hoT0QmAYbngjt3RoT2mu2mGkfwLwAnhiwfefc4/ZVLW9oz9hWRERELLXxoX162gm3/tKUbsJultAe2VYx8u61J6YtU5P6dupC++zeA5lKhLQ17W5gsiyzi9D6tjw+KvI1hY8/ku4YTjmOymBbarYZ+D4YUqtiGabYNffBwzDUvxi4JUHKc3ihvWqtf5+1bKNmi2lYUnXLUlTXEWlD4BxO+62q/zoMsapJ1xEN7TXbTP8QlDm0+9vSg9CuLfFBRETEjaQ+tAfCsROgM0+4u4xQAAAUK0lEQVQkTQztwUmiwcA8Kzt9+3YC+fS0jG2flqnIsRQhP7xFUaG9vR6Is4em/KHdUzfS7rTPH37DtdrrIdn7LFIr7QbdSAD29MJ6Z5/4evBYfWHaO0/wumpiW/6QHj7Helj39o9ce+Q6VIE3Wwjuqjym0x5daA/WtJsH49uT6SEDERERS2tCaA8GY12teCxdlMesn8ML7aEHBu9XgNDeaUpfiimPaYs/KA5ypDM+tKsDaDCUKwJ2qNwlsfxGUR6TuWRH8WCQNNEyEurD1xoqHYmGW1X/OP0R+4ASaLMlxi5DrG5LU2JDe8iTtpia4M6EVERExOGwZKE9fF4nrIcnnqqDd/Ioe/y+3aEN7d7kU7ubSahFjLTHBNBAyE4KqSlGnnsW2vV9GC7zMYxsoT3aphyh3Q3suhHw5GtOGdrb7oj+fs2vKYR2RETEDW85Q7svVKvOOTUZLdNxSltUJTMS3a7vod0tK/FPRM0UnIoI7elH2nUhtbiRdk1oV6zOk3WkPV1oT/GQkjDynf6a04Z2d3lIXWinPAYREXHDW7LQrqibd2vrOyPoyiUfo6vOxJ6hgJr2yJrsMWu3F2G0bl3zXaQMJcXIsluzrq9pTxHaO3XrirYmhPbIdXh19BlCe7Cd8aVN+pFrt948JkAH25vw95AytNcOmprtmIiKiIg4LMa/XKmQ0O6VvyS83CnwcqXosdKOsne27WdojwmxTlAbxPJ7wRVTlAHaV1ISbHfKchD/yjBxq8eEz9nD0B65RtOWamCEOUVoD/WFadekamVb8jH4YiWf4RCvuda4Y3Rq492R/M53uomuLPmIiIg4NBrp4mkO+r0OfEaKm4iKw2rV6mLZyoDdlEx1dw5G2REREYdDQnsOCO2b1S6WrfTr/jLRz0Ddywmoq82mrL4yJ61nvy8r//lfsnLgUVn68gOyvOd+Wf7H+2T5S3tk+aF/ldYz35X26moJ7g8iIuLwWVBoXy9/ybzOe08IrgVPaMf8VsXK/NKs6HrxA2tbqyWtl47LyqHDsvzAQ7L4uTtk4fq/lPnxq2T+ksukecE2aW7ZKo3TzpTGSCW1i9d8guCOiIjYB/sf2ocYQjtuGFstaR19Tpb+6SuycN0npXHOhamDeLNyjjQvukTmr/gDWdjxcVn4i0/L0k1/K4u33S5Ld94lS7d/QRavvV6a518kjZGKrHxrevDXi4iIOGQS2nNAaMey23rpuCz99S3KkN7c9i5Z+Nh1sjh5syz/w15Z+fqj0vqf/5XWS8dl9dUfyuqbb0p7eTn1uVYem3JG2z9z48CvGxERcdgktOeA0I5ldXV+XhYnPrse0n/rDJm/4gOydPOtsvKNb8rqa6/3/pxzJ52HgQu2USKDiIjYYwntOSC0YylttWT+A3/ohHVziyzecpu0Zn/Q//Ourkpz6+9KY6Qiqy+fGHw/ICIiDpGE9hwQ2rGMtl540RnxvvhSaR19rtBzL1zzZ05d+78/NvB+QEREHCYJ7TkgtKPO2jFTzGPFr5O+8vh/O7XlfzWRrp22GV1+smpFX4CVwqXddzvnvvXzG7oPERERyyahPQeDDu3OW1a9t3gq3nzZefOm0fd1wWNVvBF1M1g7ZopxeDDXvXL4cWmMVOTAr/1GYt87f0Oqbbp7OdPKt6alMVKRhQ9/NMN+VbF2GWLsUrWjKtZhQ6xXBn9PERERBymhPQf9Du3aF+TUbDF930XDV01s0xfk3QDf3/XBFQ5ZaK9aRvII9Bu2mIdNsd/oVzuclzvF3cuVz26XxkhFntx2ur7va7aYqoe9wPfZ/mZWX3vdKc3ZslXarVa6Pt1viLHHFFMZ2tvSfsUSo6/9iYiIWH4J7TkYaGiPqA9y7XbKwNlrN2Forz5jiPFMP/tZd6+r8ul3XCuNkYq8fqE+tKe5lm7erOpNRm0dn03e/qTthHXvvwPrU0RExHJLaM9BXGiv2aYYVjVYvhIOR5rSlWDZi6EvgenY+9Be/9zP5WujEvXSn0k97R+ZF9qr1vp1aH8hiF6Lsj/DQVJbCuSUeljV9TeSKt9KqjlG1VLdD0Pd9rhR4arltDumL9Tn8h/f6RdlO3z3tfX8C9IYqciPz9WF9qpY2r8nf5+k2M5nZzLq1x9N2LYm9h5DzIO19fAet+0r1sDKjRAREcsgoT0H2tDuD1LhMoNI2YETxsL1w1lGOeNrk+POmWzvQrs/nIavNfqwEb7uSH+Gj5HYn+thPfAg4O+vlPck8cFHFy4T+8I9fsaHmrBeicqbv12J/5tI/QuI98CT/u9m6fbd0hipyNKdd+m3rVli7HGvNSm06x6GEBERN4GE9hxoQ3sgbAcn9Xkjx/p9MoR2N3DGTxp0Q2vGMoeeqAiH4eAb/Hd0AmRs37j7JPenYlJlaAQ57T1JCu21Y6YYT8T0c2JfqEa/VQE9IbTPz0tjpCI/fUd8aE//QJh9QurKvx1wJqN+4gbNds7kU8u71lShnQmpiIi4eSW056Db0B5batFNaPdKOmKDpDfKnL20oKflMb7PIsG3ZovpbeP/f00/+D9L7s/k0J72nvQ1tIfKc/xmCe3tdluaZ5wrjZGK/MovXFF4aG89+z1pjFRk/j3vi++ng6YY+339SGhHRETUSmjPQS9H2tMdJ6xb46w5lhNGu6sFLiy0+0owVGuGJ414J/dndyPtsf2Zqzwm60h7/H3XhvaLL5XGSEVGfvGywstjVhtN522so2dJe2VFfcw9hhi7Ytyv6l/KYxARcXNLaM9Bt6E9dX151dJMPk0ueXHqobNNIuy5qUK7u51pRkbZlf2ZOEdA3Ve60J72niTOHdCNCKctFUocAXfvvebhYX78KmmMVOS8X3q3ZiJqir9B7URUb2JstD+aF10ijZGKrP7g5XR/J0xERURE1Epoz0HXob3dVpZCqEoQgmUboZFhXTlHbKlFwSE+bWjX/GoQvdbkF0kF+zNFaE99T4Ir0KgCa+zyhCn7Ilqqowir4baG5gTs//XflMZIRS7/5V+N7bNeLPnotTXcTwt/dI2zgszBQ+n+TljyERERUSuhPQeDfiPqcBk/8tvNWuED9Q1bzAHXXy994e+dFVy+eE/8dkm/LqRZ7tFdESd8jKWbb5XGSEWW99yf/3oYZUdERCS054HQ3jt1o74bLrS33QmpAwyare886azg8pFr9e2MLfdJMwE1fpLzcvVfpDFSkUV7Mue1MAEVERGx3Sa054LQnldfqUlSbf4GC+3tthPczWPpV13pqYuL0jz9bGlu2SrtVkvfTsXk33bV0pfORNacD9p64ilnBZkrr964fYiIiFgiCe05ILRjmV24+o+lMVKR1lNPF3/+H/3YWUHmnAsH3g+IiIjDIKE9B4R2LLPLDz/ilKh8yi783KunTkljpCLNd44NvB8QERGHQUJ7DgjtWGoXF6V5/kXSPP1sab/5ZqHnbtW+m/iCJUREREwvoT0HhHYsu0t33uWs4nLPvcWe9/bdzuo1f/N3A+8DRETEYZDQngNCO5bd1R++Js3KOdI841xZ/b9Xijnn/Lw0z7/Yqad/4qmB9wEiIuIwSGjPAaEdN4JL9/2zs/zjx66T+fd9UBqnnSnNLVulecE2mb/kMmm+9/0yf+XVsvCRa2XhT/9cFj9ly+LkzbJ46+dlaffdsnzvfbL8wFdl+eFHZOWxKVk5dFhaTz4trWe/L60Xj8vqyVed8pulJWm327L8wENOaYz1QWmvrg78+hEREYdBQnsOCO24IWy1ZP5DO5zVXPrtWRdI47zfcd6G+o1vDv7aERERh0RCew7q9brMzc0N/CYiJrn68glpvvN8ZzWZG2+S9k/ekNWTr0rrhZek9ez3pPWdJ2XlPw7J4uTNgRC+dMduWbzlNlm88SZZuOEzsvAnn5SFHR+X+Ss/LM3Lx2X+994jzQu2SXPLVmmcdmZnv/nxq6S9sjLw60ZERBwWCe05WFtbk3q9LjMzM4il96X9D8tPK2dLY6QiP3n378vLX7pXnp8+JM8f+rbM3v9lqX/4o53Q/aP3f0iee/rpzOc49u3DMvuValf7IiIiYryEdoBNxM9ePC4L73pvfHnL6Fmy+sV7RN5+e9BNBQAAAB+EdoBNxs/fekveevgRWbxqhzTPPE+aZ5wrC9svl9Ydu2XttdcH3TwAAABQQGgHAAAAACg5hHYAAAAAgJJDaAcAAAAAKDnG9YdvEERERERELK+MtAMAAAAAlBxCOwAAAABAySG0AwAAAACUHEI7AAAAAEDJIbQDAAAAAJQcQjsAAAAAQMkhtAMAAAAAlBxCew7W1takXq/LzMwMIiIiImLfJLTnoF6vy9zcnLTbbURERETEvkloz8HMzMzAbyAiIiIiDr+E9hwQ2hERERGxCAntOSC0IyIiImIREtpzQGhHRERExCIktOeA0I6IiIiIRUhozwGhHRERERGLkNCeA0I7IiIiIhYhoT0HhHZERERELML+h/YTR2R8+4My5jq+91TfTxnllNy9Y70NYzuOyGwPjjpsob1mm2LatYz71cQ2TbFrg28/IiIi4rBqjPkC9dj2B2XndA/SrJ8TR2R8+wG5+4T666nJ4PnHJhVxenpa38bQ97pQPrv3wNCE9pptimEYrorgXLPF7HxvaAO5cyxLqp3PqmIZhhhWVbFd6FxVK7QvIiIiIvZSIylU5ybT8WdlZziUh/efnpaxyL+nZaqzgzuqrgr/srFCe802xTBtqam+r9li+r6Lhu7QCLgb4K1qzLE0ob+zj+YYVcuIbysiIiIi5rJkod0J3P4SmqnJcAAPhnJVCI/us87QhPaIzsi4MpS7Vq3oyLnu8853bhv0wTz5/IiIiIjYnfGhfXraCbf+0pNuwm6W0B7ZVjHy7rWn0xZnm86/wyPxIXShfXbvgUwlQnGhvWabYljVYPlKOBRrSleCZS+GvgSmY7ehvSpWmuNaVsL59eEfEREREbtXH9oV4TjzRNLE0B6cJBoMzLOy07fv1OSDvgcJf0mMvzY++HmYwkK7P6gnlpk4wThcc55lpD1aHhMyrrQlTT161VI/eKi2o0QGERERsecmhHZFMI4pO4mli/KY9XN4oT30wOD9CuDfx/23F97jgncR5THRsF0T21wP5d5IvH6fDKHdDeTxE02d86uOleYcVSvm14KwTEhFRERE7IslC+3h87qlL6H9/cHbGR1XtFM3mj7g0N4JwWG7Ce1emU1soHYDe0yYTjyHN0JvayayehLaEREREftiOUO7L1Srzjk1uT7qrgroiSUwJRxpT3ecsOplGf06DwiaIK0N2sER+lTHojwGERERseeWLLQr6ubd2vpOuYtyycfo5NVuVo/paU27JrRrl1/0W9VN/owveQm0I2HyqG4Ca3R//UMCE1ERERER+2P8y5UKCe1e+UvCy50CL0+KHssL29oXNPm3HXRob7cjq8fEvfwoWEqzHqBjV5jxzqs4ftwKNMqwHVcn705KjYZ8lnxERERE7JdGuniag36vA5+RjbROe2GmHfnXyCg7IiIiYv8ktOdgaEJ7O8WSkTqZgIqIiIjYVwsK7eulK5nXee8JwbXgCe1qa7apWTYyzprYZlLdPCIiIiLmsf+hfYgZttCOiIiIiOWU0J4DQjsiIiIiFiGhPQeEdkREREQsQkJ7DgjtiIiIiFiEhPYcENoRERERsQgJ7TkgtCMiIiJiERLac0BoR0RERMQiJLTnoF6vy9zc3MBvIiIiIiIOt4T2HKytrUm9XpeZmRlERERExL5JaAcAAAAAKDmEdgAAAACAkkNoBwAAAAAoOYR2AAAAAICSQ2gHAAAAACg5hHYAAAAAgJJDaAcAAAAAKDmEdgAAAACAkkNoBwAAAAAoOYR2AAAAAICSQ2gHAAAAACg5hHbYgByVidFRmTga/nhCRg1DDNfRyAYbhX0y7rsOY3xfZIujE6Mb+PoAAAAgK4T2YWbfuBjGuEQjXzfH8YVI5TGPysSoIcbohPQ3SrrnUQRZJ7Qrwnzg+yJCvdtGVVtCbYjvT4d94zHX6gZ75VcAAAAwdBDa+8jRidECQqyGHoT2oxOj6vAZ3bKQ0K7tU21oD43Ou+G556HXa8PEuCa0p78n8aFd3Pub5t4AAADARofQ3keGIbRrQ2PhJIwuJ420h4/W82s7KhOjbn/HBepehvYU3wMAAMBwQGjvA87odLgEIlouEd4uXK6xb9z5zL9dtKTDK8VYt5PhvNDuL2/J+BCxbzymzCOyjeb4kfIaxTHTlK7sG9e3f+ChPXDwQkJ7z0qgAAAAoNQQ2vuIbqTdCeL+sOWMIvvDaicMe8eIhFJNfbdzgFCQjp4jxVX4Hgr0gTjtLwvew4hvx1CpirqdiQE2S2jvV3mMhza0xzxkKQ+T9GCxT8YpkQEAABh6CO19JD7EOkE4HErD2+8bD49ch8pDkkZZFd93P7rsC++6B5GE0H50YjRy/tjPAsdS91lop5ShvYD6+7T15u6DVfxzV5rQzoRUAACAYYfQ3kfiQ2xM0AqF7KTAlhiSexraO0eIHa1PbE9MaUigvMZvX0K79/DR55KS1JNE9ddFaAcAAAARQntf6clIe5565r6E9vhj6EN7zNrqoh5pz3Je34ESQ7vzgFBADXjq0K4vWaI8BgAAAEQI7f1FE9wiNe2KGuu0o6z6mvY0od17mU+K8KepBdeF9kgde8pjhg6iD9wJoT3t8pXeyH++HyTShfakhwgmogIAAIAIob3vBEs/giEuXBYSzmbpRsVDb89MqHnPFtqjK9NE2xk9f+SFQcrVY9STUXWr6eRa8lH5UqOYB5XIBN70xJX6BO+J/m2nkeOx5CMAAMCmh9AOG4roqjuBLzMt+RhPwi8YBZL8ciVG2QEAADYDhHbYYGiWuexRaPfWxS9BZteEdiagAgAAbCb+H40c+WtSWOZrAAAAAElFTkSuQmCC"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![%E5%9B%BE%E7%89%87.png](attachment:%E5%9B%BE%E7%89%87.png)这个括号是非常重要的，当net为sequential时，可没有，但如果是一个块，则需要这个，否则会报错，我想原因可能是和__call__有关，net1也进行了super().__init__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### net33  注意与net22结构的区别"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 330,
   "metadata": {},
   "outputs": [],
   "source": [
    "class net1(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.hidden1 = nn.Linear(10, 256)\n",
    "        self.hidden2 = nn.Linear(256, 128)\n",
    "        self.out = nn.Linear(128,10)\n",
    "    def forward(self, X):\n",
    "        return self.out(F.relu(self.hidden2(F.relu(self.hidden1(X)))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 331,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Factory(nn.Module):\n",
    "    def __init__(self,block, k):\n",
    "        super().__init__()\n",
    "        modules=[]\n",
    "        for i in range(k):\n",
    "            modules.append(block())\n",
    "        self.net = nn.Sequential(*modules)\n",
    "    def forward(self, X):\n",
    "        return self.net(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 332,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.1494,  0.0048,  0.0744,  0.0041, -0.0020, -0.0629,  0.0372, -0.0098,\n",
       "         -0.0460, -0.1061],\n",
       "        [ 0.1493,  0.0049,  0.0745,  0.0044, -0.0020, -0.0627,  0.0373, -0.0098,\n",
       "         -0.0460, -0.1061]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 332,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net33 = Factory(net1,3)\n",
    "X = torch.rand(2,10)\n",
    "net33(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 321,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('module.hidden1.weight', torch.Size([256, 15])) ('module.hidden1.bias', torch.Size([256])) ('module.hidden2.weight', torch.Size([128, 256])) ('module.hidden2.bias', torch.Size([128])) ('module.out.weight', torch.Size([10, 128])) ('module.out.bias', torch.Size([10])) ('linear.weight', torch.Size([15, 10])) ('linear.bias', torch.Size([15]))\n"
     ]
    }
   ],
   "source": [
    "print(*[(name, param.shape) for name, param in net22.named_parameters()])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 322,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "hypenet(\n",
       "  (module): net1(\n",
       "    (hidden1): Linear(in_features=15, out_features=256, bias=True)\n",
       "    (hidden2): Linear(in_features=256, out_features=128, bias=True)\n",
       "    (out): Linear(in_features=128, out_features=10, bias=True)\n",
       "  )\n",
       "  (linear): Linear(in_features=10, out_features=15, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 322,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net22"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 333,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Factory(\n",
       "  (net): Sequential(\n",
       "    (0): net1(\n",
       "      (hidden1): Linear(in_features=10, out_features=256, bias=True)\n",
       "      (hidden2): Linear(in_features=256, out_features=128, bias=True)\n",
       "      (out): Linear(in_features=128, out_features=10, bias=True)\n",
       "    )\n",
       "    (1): net1(\n",
       "      (hidden1): Linear(in_features=10, out_features=256, bias=True)\n",
       "      (hidden2): Linear(in_features=256, out_features=128, bias=True)\n",
       "      (out): Linear(in_features=128, out_features=10, bias=True)\n",
       "    )\n",
       "    (2): net1(\n",
       "      (hidden1): Linear(in_features=10, out_features=256, bias=True)\n",
       "      (hidden2): Linear(in_features=256, out_features=128, bias=True)\n",
       "      (out): Linear(in_features=128, out_features=10, bias=True)\n",
       "    )\n",
       "  )\n",
       ")"
      ]
     },
     "execution_count": 333,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net33"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
